From 57c6118be83d6d34f244c3a08dd16dcc92ab0498 Mon Sep 17 00:00:00 2001 From: D-Stacks <78099568+D-Stacks@users.noreply.github.com> Date: Thu, 14 Apr 2022 01:16:16 +0200 Subject: [PATCH] Adds a "sweep" command to `kaspawallet` (#2018) * Add "sweep" command to kaspawallet * minor linting & layout improvements. * contain code in "sweep" * update to sweep.go * formatting and bugs * clean up renaming of ExtractTransaction functions * Nicer formating of display * address reveiw. * one more sweeped -> swept * missed one reveiw comment. (extra mass). * remove redundant code from split function. Co-authored-by: Ori Newman --- cmd/kaspawallet/balance.go | 15 +- cmd/kaspawallet/config.go | 18 + cmd/kaspawallet/daemon/pb/kaspawalletd.pb.go | 713 +++++++++++++++--- cmd/kaspawallet/daemon/pb/kaspawalletd.proto | 40 +- .../daemon/pb/kaspawalletd_grpc.pb.go | 44 ++ cmd/kaspawallet/daemon/server/broadcast.go | 22 +- .../daemon/server/external_spendable_utxos.go | 63 ++ cmd/kaspawallet/daemon/server/send.go | 2 +- cmd/kaspawallet/libkaspawallet/converters.go | 61 ++ .../protoserialization/wallet.pb.go | 9 +- .../serialization/serialization.go | 18 +- cmd/kaspawallet/main.go | 2 + cmd/kaspawallet/sweep.go | 242 ++++++ cmd/kaspawallet/utils/format_kas.go | 16 + .../database/serialization/dbobjects.pb.go | 9 +- .../network/dnsseed/pb/peer_service.pb.go | 9 +- .../dnsseed/pb/peer_service_grpc.pb.go | 27 +- .../grpcserver/protowire/messages.pb.go | 9 +- .../grpcserver/protowire/messages_grpc.pb.go | 51 +- .../server/grpcserver/protowire/p2p.pb.go | 9 +- .../server/grpcserver/protowire/rpc.pb.go | 9 +- 21 files changed, 1190 insertions(+), 198 deletions(-) create mode 100644 cmd/kaspawallet/daemon/server/external_spendable_utxos.go create mode 100644 cmd/kaspawallet/libkaspawallet/converters.go create mode 100644 cmd/kaspawallet/sweep.go create mode 100644 cmd/kaspawallet/utils/format_kas.go diff --git a/cmd/kaspawallet/balance.go b/cmd/kaspawallet/balance.go index cc594257c..1f3df3feb 100644 --- a/cmd/kaspawallet/balance.go +++ b/cmd/kaspawallet/balance.go @@ -3,19 +3,12 @@ package main import ( "context" "fmt" + "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client" "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/cmd/kaspawallet/utils" ) -func formatKas(amount uint64) string { - res := " " - if amount > 0 { - res = fmt.Sprintf("%19.8f", float64(amount)/constants.SompiPerKaspa) - } - return res -} - func balance(conf *balanceConfig) error { daemonClient, tearDown, err := client.Connect(conf.DaemonAddress) if err != nil { @@ -39,12 +32,12 @@ func balance(conf *balanceConfig) error { println("Address Available Pending") println("-----------------------------------------------------------------------------------------------------------") for _, addressBalance := range response.AddressBalances { - fmt.Printf("%s %s %s\n", addressBalance.Address, formatKas(addressBalance.Available), formatKas(addressBalance.Pending)) + fmt.Printf("%s %s %s\n", addressBalance.Address, utils.FormatKas(addressBalance.Available), utils.FormatKas(addressBalance.Pending)) } println("-----------------------------------------------------------------------------------------------------------") print(" ") } - fmt.Printf("Total balance, KAS %s %s%s\n", formatKas(response.Available), formatKas(response.Pending), pendingSuffix) + fmt.Printf("Total balance, KAS %s %s%s\n", utils.FormatKas(response.Available), utils.FormatKas(response.Pending), pendingSuffix) return nil } diff --git a/cmd/kaspawallet/config.go b/cmd/kaspawallet/config.go index 2ef719669..12de108da 100644 --- a/cmd/kaspawallet/config.go +++ b/cmd/kaspawallet/config.go @@ -13,6 +13,7 @@ const ( createSubCmd = "create" balanceSubCmd = "balance" sendSubCmd = "send" + sweepSubCmd = "sweep" createUnsignedTransactionSubCmd = "create-unsigned-transaction" signSubCmd = "sign" broadcastSubCmd = "broadcast" @@ -59,6 +60,12 @@ type sendConfig struct { config.NetworkFlags } +type sweepConfig struct { + PrivateKey string `long:"private-key" short:"k" description:"Private key in hex format"` + DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to (default: localhost:8082)"` + config.NetworkFlags +} + type createUnsignedTransactionConfig struct { DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to (default: localhost:8082)"` ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"` @@ -130,6 +137,10 @@ func parseCommandLine() (subCommand string, config interface{}) { parser.AddCommand(sendSubCmd, "Sends a Kaspa transaction to a public address", "Sends a Kaspa transaction to a public address", sendConf) + sweepConf := &sweepConfig{DaemonAddress: defaultListen} + parser.AddCommand(sweepSubCmd, "Sends all funds associated with the given private key, to a new address of the wallet", + "Sends all funds associated with the private key, to a given change address of the wallet", sweepConf) + createUnsignedTransactionConf := &createUnsignedTransactionConfig{DaemonAddress: defaultListen} parser.AddCommand(createUnsignedTransactionSubCmd, "Create an unsigned Kaspa transaction", "Create an unsigned Kaspa transaction", createUnsignedTransactionConf) @@ -199,6 +210,13 @@ func parseCommandLine() (subCommand string, config interface{}) { printErrorAndExit(err) } config = sendConf + case sweepSubCmd: + combineNetworkFlags(&sweepConf.NetworkFlags, &cfg.NetworkFlags) + err := sweepConf.ResolveNetwork(parser) + if err != nil { + printErrorAndExit(err) + } + config = sweepConf case createUnsignedTransactionSubCmd: combineNetworkFlags(&createUnsignedTransactionConf.NetworkFlags, &cfg.NetworkFlags) err := createUnsignedTransactionConf.ResolveNetwork(parser) diff --git a/cmd/kaspawallet/daemon/pb/kaspawalletd.pb.go b/cmd/kaspawallet/daemon/pb/kaspawalletd.pb.go index 3796787f0..2e9f421b8 100644 --- a/cmd/kaspawallet/daemon/pb/kaspawalletd.pb.go +++ b/cmd/kaspawallet/daemon/pb/kaspawalletd.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.19.4 +// protoc-gen-go v1.28.0 +// protoc v3.17.2 // source: kaspawalletd.proto package pb @@ -461,7 +461,8 @@ type BroadcastRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Transactions [][]byte `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"` + IsDomain bool `protobuf:"varint,1,opt,name=isDomain,proto3" json:"isDomain,omitempty"` + Transactions [][]byte `protobuf:"bytes,2,rep,name=transactions,proto3" json:"transactions,omitempty"` } func (x *BroadcastRequest) Reset() { @@ -496,6 +497,13 @@ func (*BroadcastRequest) Descriptor() ([]byte, []int) { return file_kaspawalletd_proto_rawDescGZIP(), []int{9} } +func (x *BroadcastRequest) GetIsDomain() bool { + if x != nil { + return x.IsDomain + } + return false +} + func (x *BroadcastRequest) GetTransactions() [][]byte { if x != nil { return x.Transactions @@ -626,6 +634,345 @@ func (*ShutdownResponse) Descriptor() ([]byte, []int) { return file_kaspawalletd_proto_rawDescGZIP(), []int{12} } +type Outpoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TransactionId string `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` +} + +func (x *Outpoint) Reset() { + *x = Outpoint{} + if protoimpl.UnsafeEnabled { + mi := &file_kaspawalletd_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Outpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Outpoint) ProtoMessage() {} + +func (x *Outpoint) ProtoReflect() protoreflect.Message { + mi := &file_kaspawalletd_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Outpoint.ProtoReflect.Descriptor instead. +func (*Outpoint) Descriptor() ([]byte, []int) { + return file_kaspawalletd_proto_rawDescGZIP(), []int{13} +} + +func (x *Outpoint) GetTransactionId() string { + if x != nil { + return x.TransactionId + } + return "" +} + +func (x *Outpoint) GetIndex() uint32 { + if x != nil { + return x.Index + } + return 0 +} + +type UtxosByAddressesEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Outpoint *Outpoint `protobuf:"bytes,2,opt,name=outpoint,proto3" json:"outpoint,omitempty"` + UtxoEntry *UtxoEntry `protobuf:"bytes,3,opt,name=utxoEntry,proto3" json:"utxoEntry,omitempty"` +} + +func (x *UtxosByAddressesEntry) Reset() { + *x = UtxosByAddressesEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_kaspawalletd_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UtxosByAddressesEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UtxosByAddressesEntry) ProtoMessage() {} + +func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { + mi := &file_kaspawalletd_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UtxosByAddressesEntry.ProtoReflect.Descriptor instead. +func (*UtxosByAddressesEntry) Descriptor() ([]byte, []int) { + return file_kaspawalletd_proto_rawDescGZIP(), []int{14} +} + +func (x *UtxosByAddressesEntry) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *UtxosByAddressesEntry) GetOutpoint() *Outpoint { + if x != nil { + return x.Outpoint + } + return nil +} + +func (x *UtxosByAddressesEntry) GetUtxoEntry() *UtxoEntry { + if x != nil { + return x.UtxoEntry + } + return nil +} + +type ScriptPublicKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + ScriptPublicKey string `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` +} + +func (x *ScriptPublicKey) Reset() { + *x = ScriptPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_kaspawalletd_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScriptPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScriptPublicKey) ProtoMessage() {} + +func (x *ScriptPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_kaspawalletd_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScriptPublicKey.ProtoReflect.Descriptor instead. +func (*ScriptPublicKey) Descriptor() ([]byte, []int) { + return file_kaspawalletd_proto_rawDescGZIP(), []int{15} +} + +func (x *ScriptPublicKey) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *ScriptPublicKey) GetScriptPublicKey() string { + if x != nil { + return x.ScriptPublicKey + } + return "" +} + +type UtxoEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPublicKey *ScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` + BlockDaaScore uint64 `protobuf:"varint,3,opt,name=blockDaaScore,proto3" json:"blockDaaScore,omitempty"` + IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` +} + +func (x *UtxoEntry) Reset() { + *x = UtxoEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_kaspawalletd_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UtxoEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UtxoEntry) ProtoMessage() {} + +func (x *UtxoEntry) ProtoReflect() protoreflect.Message { + mi := &file_kaspawalletd_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UtxoEntry.ProtoReflect.Descriptor instead. +func (*UtxoEntry) Descriptor() ([]byte, []int) { + return file_kaspawalletd_proto_rawDescGZIP(), []int{16} +} + +func (x *UtxoEntry) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *UtxoEntry) GetScriptPublicKey() *ScriptPublicKey { + if x != nil { + return x.ScriptPublicKey + } + return nil +} + +func (x *UtxoEntry) GetBlockDaaScore() uint64 { + if x != nil { + return x.BlockDaaScore + } + return 0 +} + +func (x *UtxoEntry) GetIsCoinbase() bool { + if x != nil { + return x.IsCoinbase + } + return false +} + +type GetExternalSpendableUTXOsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +} + +func (x *GetExternalSpendableUTXOsRequest) Reset() { + *x = GetExternalSpendableUTXOsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kaspawalletd_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetExternalSpendableUTXOsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetExternalSpendableUTXOsRequest) ProtoMessage() {} + +func (x *GetExternalSpendableUTXOsRequest) ProtoReflect() protoreflect.Message { + mi := &file_kaspawalletd_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetExternalSpendableUTXOsRequest.ProtoReflect.Descriptor instead. +func (*GetExternalSpendableUTXOsRequest) Descriptor() ([]byte, []int) { + return file_kaspawalletd_proto_rawDescGZIP(), []int{17} +} + +func (x *GetExternalSpendableUTXOsRequest) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +type GetExternalSpendableUTXOsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Entries []*UtxosByAddressesEntry `protobuf:"bytes,1,rep,name=Entries,proto3" json:"Entries,omitempty"` +} + +func (x *GetExternalSpendableUTXOsResponse) Reset() { + *x = GetExternalSpendableUTXOsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_kaspawalletd_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetExternalSpendableUTXOsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetExternalSpendableUTXOsResponse) ProtoMessage() {} + +func (x *GetExternalSpendableUTXOsResponse) ProtoReflect() protoreflect.Message { + mi := &file_kaspawalletd_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetExternalSpendableUTXOsResponse.ProtoReflect.Descriptor instead. +func (*GetExternalSpendableUTXOsResponse) Descriptor() ([]byte, []int) { + return file_kaspawalletd_proto_rawDescGZIP(), []int{18} +} + +func (x *GetExternalSpendableUTXOsResponse) GetEntries() []*UtxosByAddressesEntry { + if x != nil { + return x.Entries + } + return nil +} + +// Since SendRequest contains a password - this command should only be used on a trusted or secure connection type SendRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -639,7 +986,7 @@ type SendRequest struct { func (x *SendRequest) Reset() { *x = SendRequest{} if protoimpl.UnsafeEnabled { - mi := &file_kaspawalletd_proto_msgTypes[13] + mi := &file_kaspawalletd_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -652,7 +999,7 @@ func (x *SendRequest) String() string { func (*SendRequest) ProtoMessage() {} func (x *SendRequest) ProtoReflect() protoreflect.Message { - mi := &file_kaspawalletd_proto_msgTypes[13] + mi := &file_kaspawalletd_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -665,7 +1012,7 @@ func (x *SendRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SendRequest.ProtoReflect.Descriptor instead. func (*SendRequest) Descriptor() ([]byte, []int) { - return file_kaspawalletd_proto_rawDescGZIP(), []int{13} + return file_kaspawalletd_proto_rawDescGZIP(), []int{19} } func (x *SendRequest) GetToAddress() string { @@ -700,7 +1047,7 @@ type SendResponse struct { func (x *SendResponse) Reset() { *x = SendResponse{} if protoimpl.UnsafeEnabled { - mi := &file_kaspawalletd_proto_msgTypes[14] + mi := &file_kaspawalletd_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -713,7 +1060,7 @@ func (x *SendResponse) String() string { func (*SendResponse) ProtoMessage() {} func (x *SendResponse) ProtoReflect() protoreflect.Message { - mi := &file_kaspawalletd_proto_msgTypes[14] + mi := &file_kaspawalletd_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -726,7 +1073,7 @@ func (x *SendResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SendResponse.ProtoReflect.Descriptor instead. func (*SendResponse) Descriptor() ([]byte, []int) { - return file_kaspawalletd_proto_rawDescGZIP(), []int{14} + return file_kaspawalletd_proto_rawDescGZIP(), []int{20} } func (x *SendResponse) GetTxIDs() []string { @@ -736,6 +1083,7 @@ func (x *SendResponse) GetTxIDs() []string { return nil } +// Since SignRequest contains a password - this command should only be used on a trusted or secure connection type SignRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -748,7 +1096,7 @@ type SignRequest struct { func (x *SignRequest) Reset() { *x = SignRequest{} if protoimpl.UnsafeEnabled { - mi := &file_kaspawalletd_proto_msgTypes[15] + mi := &file_kaspawalletd_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -761,7 +1109,7 @@ func (x *SignRequest) String() string { func (*SignRequest) ProtoMessage() {} func (x *SignRequest) ProtoReflect() protoreflect.Message { - mi := &file_kaspawalletd_proto_msgTypes[15] + mi := &file_kaspawalletd_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -774,7 +1122,7 @@ func (x *SignRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SignRequest.ProtoReflect.Descriptor instead. func (*SignRequest) Descriptor() ([]byte, []int) { - return file_kaspawalletd_proto_rawDescGZIP(), []int{15} + return file_kaspawalletd_proto_rawDescGZIP(), []int{21} } func (x *SignRequest) GetUnsignedTransactions() [][]byte { @@ -802,7 +1150,7 @@ type SignResponse struct { func (x *SignResponse) Reset() { *x = SignResponse{} if protoimpl.UnsafeEnabled { - mi := &file_kaspawalletd_proto_msgTypes[16] + mi := &file_kaspawalletd_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -815,7 +1163,7 @@ func (x *SignResponse) String() string { func (*SignResponse) ProtoMessage() {} func (x *SignResponse) ProtoReflect() protoreflect.Message { - mi := &file_kaspawalletd_proto_msgTypes[16] + mi := &file_kaspawalletd_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -828,7 +1176,7 @@ func (x *SignResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SignResponse.ProtoReflect.Descriptor instead. func (*SignResponse) Descriptor() ([]byte, []int) { - return file_kaspawalletd_proto_rawDescGZIP(), []int{16} + return file_kaspawalletd_proto_rawDescGZIP(), []int{22} } func (x *SignResponse) GetSignedTransactions() [][]byte { @@ -880,81 +1228,132 @@ var file_kaspawalletd_proto_rawDesc = []byte{ 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x36, 0x0a, 0x10, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, - 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, - 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x29, 0x0a, - 0x11, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, 0x74, - 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x53, - 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x5f, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x22, 0x5d, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0c, 0x52, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x3e, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0c, 0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xb3, 0x05, 0x0a, 0x0c, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x12, 0x51, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, 0x0a, 0x10, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x44, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x44, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x29, 0x0a, 0x11, 0x42, 0x72, 0x6f, + 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, + 0x78, 0x49, 0x44, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x68, 0x75, 0x74, 0x64, + 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x08, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, + 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6b, 0x61, 0x73, 0x70, + 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x55, 0x74, + 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x22, 0x55, 0x0a, 0x0f, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0xb2, 0x01, 0x0a, 0x09, 0x55, 0x74, + 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x3c, + 0x0a, 0x20, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, + 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x62, 0x0a, 0x21, + 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, + 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3d, 0x0a, 0x07, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x64, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, + 0x22, 0x5f, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x78, 0x49, 0x44, 0x73, 0x22, 0x5d, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0c, 0x52, 0x14, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x3e, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0c, 0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xb3, 0x06, 0x0a, 0x0c, 0x6b, 0x61, 0x73, 0x70, 0x61, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x12, 0x51, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a, 0x1a, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e, - 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6b, 0x61, 0x73, 0x70, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x19, 0x47, 0x65, + 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, + 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x12, 0x2e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a, 0x1a, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, - 0x0d, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x22, - 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, - 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x64, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x4e, 0x65, 0x77, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6b, 0x61, 0x73, + 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, + 0x0a, 0x0d, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, + 0x22, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, + 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x64, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x4e, 0x65, + 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x08, - 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, + 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, + 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, + 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x2e, 0x6b, 0x61, 0x73, 0x70, + 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x09, 0x42, 0x72, 0x6f, - 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x53, 0x65, 0x6e, - 0x64, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, - 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6b, - 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x53, 0x69, - 0x67, 0x6e, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x64, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, - 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x69, 0x67, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, - 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x6b, 0x61, - 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, - 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x09, 0x42, 0x72, + 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x53, 0x65, + 0x6e, 0x64, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, + 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x65, 0x6e, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x53, + 0x69, 0x67, 0x6e, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x64, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x69, + 0x67, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, + 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x6b, + 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x64, 0x61, 0x65, 0x6d, 0x6f, + 0x6e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -969,7 +1368,7 @@ func file_kaspawalletd_proto_rawDescGZIP() []byte { return file_kaspawalletd_proto_rawDescData } -var file_kaspawalletd_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_kaspawalletd_proto_msgTypes = make([]protoimpl.MessageInfo, 23) var file_kaspawalletd_proto_goTypes = []interface{}{ (*GetBalanceRequest)(nil), // 0: kaspawalletd.GetBalanceRequest (*GetBalanceResponse)(nil), // 1: kaspawalletd.GetBalanceResponse @@ -984,34 +1383,46 @@ var file_kaspawalletd_proto_goTypes = []interface{}{ (*BroadcastResponse)(nil), // 10: kaspawalletd.BroadcastResponse (*ShutdownRequest)(nil), // 11: kaspawalletd.ShutdownRequest (*ShutdownResponse)(nil), // 12: kaspawalletd.ShutdownResponse - (*SendRequest)(nil), // 13: kaspawalletd.SendRequest - (*SendResponse)(nil), // 14: kaspawalletd.SendResponse - (*SignRequest)(nil), // 15: kaspawalletd.SignRequest - (*SignResponse)(nil), // 16: kaspawalletd.SignResponse + (*Outpoint)(nil), // 13: kaspawalletd.Outpoint + (*UtxosByAddressesEntry)(nil), // 14: kaspawalletd.UtxosByAddressesEntry + (*ScriptPublicKey)(nil), // 15: kaspawalletd.ScriptPublicKey + (*UtxoEntry)(nil), // 16: kaspawalletd.UtxoEntry + (*GetExternalSpendableUTXOsRequest)(nil), // 17: kaspawalletd.GetExternalSpendableUTXOsRequest + (*GetExternalSpendableUTXOsResponse)(nil), // 18: kaspawalletd.GetExternalSpendableUTXOsResponse + (*SendRequest)(nil), // 19: kaspawalletd.SendRequest + (*SendResponse)(nil), // 20: kaspawalletd.SendResponse + (*SignRequest)(nil), // 21: kaspawalletd.SignRequest + (*SignResponse)(nil), // 22: kaspawalletd.SignResponse } var file_kaspawalletd_proto_depIdxs = []int32{ 2, // 0: kaspawalletd.GetBalanceResponse.addressBalances:type_name -> kaspawalletd.AddressBalances - 0, // 1: kaspawalletd.kaspawalletd.GetBalance:input_type -> kaspawalletd.GetBalanceRequest - 3, // 2: kaspawalletd.kaspawalletd.CreateUnsignedTransactions:input_type -> kaspawalletd.CreateUnsignedTransactionsRequest - 5, // 3: kaspawalletd.kaspawalletd.ShowAddresses:input_type -> kaspawalletd.ShowAddressesRequest - 7, // 4: kaspawalletd.kaspawalletd.NewAddress:input_type -> kaspawalletd.NewAddressRequest - 11, // 5: kaspawalletd.kaspawalletd.Shutdown:input_type -> kaspawalletd.ShutdownRequest - 9, // 6: kaspawalletd.kaspawalletd.Broadcast:input_type -> kaspawalletd.BroadcastRequest - 13, // 7: kaspawalletd.kaspawalletd.Send:input_type -> kaspawalletd.SendRequest - 15, // 8: kaspawalletd.kaspawalletd.Sign:input_type -> kaspawalletd.SignRequest - 1, // 9: kaspawalletd.kaspawalletd.GetBalance:output_type -> kaspawalletd.GetBalanceResponse - 4, // 10: kaspawalletd.kaspawalletd.CreateUnsignedTransactions:output_type -> kaspawalletd.CreateUnsignedTransactionsResponse - 6, // 11: kaspawalletd.kaspawalletd.ShowAddresses:output_type -> kaspawalletd.ShowAddressesResponse - 8, // 12: kaspawalletd.kaspawalletd.NewAddress:output_type -> kaspawalletd.NewAddressResponse - 12, // 13: kaspawalletd.kaspawalletd.Shutdown:output_type -> kaspawalletd.ShutdownResponse - 10, // 14: kaspawalletd.kaspawalletd.Broadcast:output_type -> kaspawalletd.BroadcastResponse - 14, // 15: kaspawalletd.kaspawalletd.Send:output_type -> kaspawalletd.SendResponse - 16, // 16: kaspawalletd.kaspawalletd.Sign:output_type -> kaspawalletd.SignResponse - 9, // [9:17] is the sub-list for method output_type - 1, // [1:9] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 13, // 1: kaspawalletd.UtxosByAddressesEntry.outpoint:type_name -> kaspawalletd.Outpoint + 16, // 2: kaspawalletd.UtxosByAddressesEntry.utxoEntry:type_name -> kaspawalletd.UtxoEntry + 15, // 3: kaspawalletd.UtxoEntry.scriptPublicKey:type_name -> kaspawalletd.ScriptPublicKey + 14, // 4: kaspawalletd.GetExternalSpendableUTXOsResponse.Entries:type_name -> kaspawalletd.UtxosByAddressesEntry + 0, // 5: kaspawalletd.kaspawalletd.GetBalance:input_type -> kaspawalletd.GetBalanceRequest + 17, // 6: kaspawalletd.kaspawalletd.GetExternalSpendableUTXOs:input_type -> kaspawalletd.GetExternalSpendableUTXOsRequest + 3, // 7: kaspawalletd.kaspawalletd.CreateUnsignedTransactions:input_type -> kaspawalletd.CreateUnsignedTransactionsRequest + 5, // 8: kaspawalletd.kaspawalletd.ShowAddresses:input_type -> kaspawalletd.ShowAddressesRequest + 7, // 9: kaspawalletd.kaspawalletd.NewAddress:input_type -> kaspawalletd.NewAddressRequest + 11, // 10: kaspawalletd.kaspawalletd.Shutdown:input_type -> kaspawalletd.ShutdownRequest + 9, // 11: kaspawalletd.kaspawalletd.Broadcast:input_type -> kaspawalletd.BroadcastRequest + 19, // 12: kaspawalletd.kaspawalletd.Send:input_type -> kaspawalletd.SendRequest + 21, // 13: kaspawalletd.kaspawalletd.Sign:input_type -> kaspawalletd.SignRequest + 1, // 14: kaspawalletd.kaspawalletd.GetBalance:output_type -> kaspawalletd.GetBalanceResponse + 18, // 15: kaspawalletd.kaspawalletd.GetExternalSpendableUTXOs:output_type -> kaspawalletd.GetExternalSpendableUTXOsResponse + 4, // 16: kaspawalletd.kaspawalletd.CreateUnsignedTransactions:output_type -> kaspawalletd.CreateUnsignedTransactionsResponse + 6, // 17: kaspawalletd.kaspawalletd.ShowAddresses:output_type -> kaspawalletd.ShowAddressesResponse + 8, // 18: kaspawalletd.kaspawalletd.NewAddress:output_type -> kaspawalletd.NewAddressResponse + 12, // 19: kaspawalletd.kaspawalletd.Shutdown:output_type -> kaspawalletd.ShutdownResponse + 10, // 20: kaspawalletd.kaspawalletd.Broadcast:output_type -> kaspawalletd.BroadcastResponse + 20, // 21: kaspawalletd.kaspawalletd.Send:output_type -> kaspawalletd.SendResponse + 22, // 22: kaspawalletd.kaspawalletd.Sign:output_type -> kaspawalletd.SignResponse + 14, // [14:23] is the sub-list for method output_type + 5, // [5:14] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_kaspawalletd_proto_init() } @@ -1177,7 +1588,7 @@ func file_kaspawalletd_proto_init() { } } file_kaspawalletd_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendRequest); i { + switch v := v.(*Outpoint); i { case 0: return &v.state case 1: @@ -1189,7 +1600,7 @@ func file_kaspawalletd_proto_init() { } } file_kaspawalletd_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendResponse); i { + switch v := v.(*UtxosByAddressesEntry); i { case 0: return &v.state case 1: @@ -1201,7 +1612,7 @@ func file_kaspawalletd_proto_init() { } } file_kaspawalletd_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SignRequest); i { + switch v := v.(*ScriptPublicKey); i { case 0: return &v.state case 1: @@ -1213,6 +1624,78 @@ func file_kaspawalletd_proto_init() { } } file_kaspawalletd_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UtxoEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kaspawalletd_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetExternalSpendableUTXOsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kaspawalletd_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetExternalSpendableUTXOsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kaspawalletd_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kaspawalletd_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kaspawalletd_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kaspawalletd_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SignResponse); i { case 0: return &v.state @@ -1231,7 +1714,7 @@ func file_kaspawalletd_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_kaspawalletd_proto_rawDesc, NumEnums: 0, - NumMessages: 17, + NumMessages: 23, NumExtensions: 0, NumServices: 1, }, diff --git a/cmd/kaspawallet/daemon/pb/kaspawalletd.proto b/cmd/kaspawallet/daemon/pb/kaspawalletd.proto index 452254ed1..7b841fe32 100644 --- a/cmd/kaspawallet/daemon/pb/kaspawalletd.proto +++ b/cmd/kaspawallet/daemon/pb/kaspawalletd.proto @@ -5,6 +5,7 @@ package kaspawalletd; service kaspawalletd { rpc GetBalance (GetBalanceRequest) returns (GetBalanceResponse) {} + rpc GetExternalSpendableUTXOs (GetExternalSpendableUTXOsRequest) returns (GetExternalSpendableUTXOsResponse) {} rpc CreateUnsignedTransactions (CreateUnsignedTransactionsRequest) returns (CreateUnsignedTransactionsResponse) {} rpc ShowAddresses (ShowAddressesRequest) returns (ShowAddressesResponse) {} rpc NewAddress (NewAddressRequest) returns (NewAddressResponse) {} @@ -26,9 +27,9 @@ message GetBalanceResponse { } message AddressBalances { - string address = 1; - uint64 available = 2; - uint64 pending = 3; + string address = 1; + uint64 available = 2; + uint64 pending = 3; } message CreateUnsignedTransactionsRequest { @@ -55,7 +56,8 @@ message NewAddressResponse { } message BroadcastRequest { - repeated bytes transactions = 1; + bool isDomain = 1; + repeated bytes transactions = 2; } message BroadcastResponse { @@ -68,6 +70,36 @@ message ShutdownRequest { message ShutdownResponse { } +message Outpoint { + string transactionId = 1; + uint32 index = 2; +} + +message UtxosByAddressesEntry { + string address = 1; + Outpoint outpoint = 2; + UtxoEntry utxoEntry = 3; +} + +message ScriptPublicKey { + uint32 version = 1; + string scriptPublicKey = 2; +} + +message UtxoEntry { + uint64 amount = 1; + ScriptPublicKey scriptPublicKey = 2; + uint64 blockDaaScore = 3; + bool isCoinbase = 4; +} + +message GetExternalSpendableUTXOsRequest{ + string address = 1; +} + +message GetExternalSpendableUTXOsResponse{ + repeated UtxosByAddressesEntry Entries = 1; +} // Since SendRequest contains a password - this command should only be used on a trusted or secure connection message SendRequest{ string toAddress = 1; diff --git a/cmd/kaspawallet/daemon/pb/kaspawalletd_grpc.pb.go b/cmd/kaspawallet/daemon/pb/kaspawalletd_grpc.pb.go index 29d78a104..ec5b02f01 100644 --- a/cmd/kaspawallet/daemon/pb/kaspawalletd_grpc.pb.go +++ b/cmd/kaspawallet/daemon/pb/kaspawalletd_grpc.pb.go @@ -1,4 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.17.2 +// source: kaspawalletd.proto package pb @@ -19,12 +23,15 @@ const _ = grpc.SupportPackageIsVersion7 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type KaspawalletdClient interface { GetBalance(ctx context.Context, in *GetBalanceRequest, opts ...grpc.CallOption) (*GetBalanceResponse, error) + GetExternalSpendableUTXOs(ctx context.Context, in *GetExternalSpendableUTXOsRequest, opts ...grpc.CallOption) (*GetExternalSpendableUTXOsResponse, error) CreateUnsignedTransactions(ctx context.Context, in *CreateUnsignedTransactionsRequest, opts ...grpc.CallOption) (*CreateUnsignedTransactionsResponse, error) ShowAddresses(ctx context.Context, in *ShowAddressesRequest, opts ...grpc.CallOption) (*ShowAddressesResponse, error) NewAddress(ctx context.Context, in *NewAddressRequest, opts ...grpc.CallOption) (*NewAddressResponse, error) Shutdown(ctx context.Context, in *ShutdownRequest, opts ...grpc.CallOption) (*ShutdownResponse, error) Broadcast(ctx context.Context, in *BroadcastRequest, opts ...grpc.CallOption) (*BroadcastResponse, error) + // Since SendRequest contains a password - this command should only be used on a trusted or secure connection Send(ctx context.Context, in *SendRequest, opts ...grpc.CallOption) (*SendResponse, error) + // Since SignRequest contains a password - this command should only be used on a trusted or secure connection Sign(ctx context.Context, in *SignRequest, opts ...grpc.CallOption) (*SignResponse, error) } @@ -45,6 +52,15 @@ func (c *kaspawalletdClient) GetBalance(ctx context.Context, in *GetBalanceReque return out, nil } +func (c *kaspawalletdClient) GetExternalSpendableUTXOs(ctx context.Context, in *GetExternalSpendableUTXOsRequest, opts ...grpc.CallOption) (*GetExternalSpendableUTXOsResponse, error) { + out := new(GetExternalSpendableUTXOsResponse) + err := c.cc.Invoke(ctx, "/kaspawalletd.kaspawalletd/GetExternalSpendableUTXOs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *kaspawalletdClient) CreateUnsignedTransactions(ctx context.Context, in *CreateUnsignedTransactionsRequest, opts ...grpc.CallOption) (*CreateUnsignedTransactionsResponse, error) { out := new(CreateUnsignedTransactionsResponse) err := c.cc.Invoke(ctx, "/kaspawalletd.kaspawalletd/CreateUnsignedTransactions", in, out, opts...) @@ -113,12 +129,15 @@ func (c *kaspawalletdClient) Sign(ctx context.Context, in *SignRequest, opts ... // for forward compatibility type KaspawalletdServer interface { GetBalance(context.Context, *GetBalanceRequest) (*GetBalanceResponse, error) + GetExternalSpendableUTXOs(context.Context, *GetExternalSpendableUTXOsRequest) (*GetExternalSpendableUTXOsResponse, error) CreateUnsignedTransactions(context.Context, *CreateUnsignedTransactionsRequest) (*CreateUnsignedTransactionsResponse, error) ShowAddresses(context.Context, *ShowAddressesRequest) (*ShowAddressesResponse, error) NewAddress(context.Context, *NewAddressRequest) (*NewAddressResponse, error) Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error) Broadcast(context.Context, *BroadcastRequest) (*BroadcastResponse, error) + // Since SendRequest contains a password - this command should only be used on a trusted or secure connection Send(context.Context, *SendRequest) (*SendResponse, error) + // Since SignRequest contains a password - this command should only be used on a trusted or secure connection Sign(context.Context, *SignRequest) (*SignResponse, error) mustEmbedUnimplementedKaspawalletdServer() } @@ -130,6 +149,9 @@ type UnimplementedKaspawalletdServer struct { func (UnimplementedKaspawalletdServer) GetBalance(context.Context, *GetBalanceRequest) (*GetBalanceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetBalance not implemented") } +func (UnimplementedKaspawalletdServer) GetExternalSpendableUTXOs(context.Context, *GetExternalSpendableUTXOsRequest) (*GetExternalSpendableUTXOsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetExternalSpendableUTXOs not implemented") +} func (UnimplementedKaspawalletdServer) CreateUnsignedTransactions(context.Context, *CreateUnsignedTransactionsRequest) (*CreateUnsignedTransactionsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateUnsignedTransactions not implemented") } @@ -182,6 +204,24 @@ func _Kaspawalletd_GetBalance_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Kaspawalletd_GetExternalSpendableUTXOs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetExternalSpendableUTXOsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KaspawalletdServer).GetExternalSpendableUTXOs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kaspawalletd.kaspawalletd/GetExternalSpendableUTXOs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KaspawalletdServer).GetExternalSpendableUTXOs(ctx, req.(*GetExternalSpendableUTXOsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Kaspawalletd_CreateUnsignedTransactions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreateUnsignedTransactionsRequest) if err := dec(in); err != nil { @@ -319,6 +359,10 @@ var Kaspawalletd_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetBalance", Handler: _Kaspawalletd_GetBalance_Handler, }, + { + MethodName: "GetExternalSpendableUTXOs", + Handler: _Kaspawalletd_GetExternalSpendableUTXOs_Handler, + }, { MethodName: "CreateUnsignedTransactions", Handler: _Kaspawalletd_CreateUnsignedTransactions_Handler, diff --git a/cmd/kaspawallet/daemon/server/broadcast.go b/cmd/kaspawallet/daemon/server/broadcast.go index e4ac096c7..9468e5c46 100644 --- a/cmd/kaspawallet/daemon/server/broadcast.go +++ b/cmd/kaspawallet/daemon/server/broadcast.go @@ -6,13 +6,14 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb" "github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet" + "github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet/serialization" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/network/rpcclient" "github.com/pkg/errors" ) func (s *server) Broadcast(_ context.Context, request *pb.BroadcastRequest) (*pb.BroadcastResponse, error) { - txIDs, err := s.broadcast(request.Transactions) + txIDs, err := s.broadcast(request.Transactions, request.IsDomain) if err != nil { return nil, err } @@ -20,13 +21,24 @@ func (s *server) Broadcast(_ context.Context, request *pb.BroadcastRequest) (*pb return &pb.BroadcastResponse{TxIDs: txIDs}, nil } -func (s *server) broadcast(transactions [][]byte) ([]string, error) { +func (s *server) broadcast(transactions [][]byte, isDomain bool) ([]string, error) { + txIDs := make([]string, len(transactions)) + var tx *externalapi.DomainTransaction + var err error for i, transaction := range transactions { - tx, err := libkaspawallet.ExtractTransaction(transaction, s.keysFile.ECDSA) - if err != nil { - return nil, err + + if isDomain { + tx, err = serialization.DeserializeDomainTransaction(transaction) + if err != nil { + return nil, err + } + } else if !isDomain { //default in proto3 is false + tx, err = libkaspawallet.ExtractTransaction(transaction, s.keysFile.ECDSA) + if err != nil { + return nil, err + } } txIDs[i], err = sendTransaction(s.rpcClient, tx) diff --git a/cmd/kaspawallet/daemon/server/external_spendable_utxos.go b/cmd/kaspawallet/daemon/server/external_spendable_utxos.go new file mode 100644 index 000000000..2d0fe597a --- /dev/null +++ b/cmd/kaspawallet/daemon/server/external_spendable_utxos.go @@ -0,0 +1,63 @@ +package server + +import ( + "context" + + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb" + "github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet" + "github.com/kaspanet/kaspad/util" +) + +func (s *server) GetExternalSpendableUTXOs(_ context.Context, request *pb.GetExternalSpendableUTXOsRequest) (*pb.GetExternalSpendableUTXOsResponse, error) { + s.lock.RLock() + defer s.lock.RUnlock() + + _, err := util.DecodeAddress(request.Address, s.params.Prefix) + if err != nil { + return nil, err + } + externalUTXOs, err := s.rpcClient.GetUTXOsByAddresses([]string{request.Address}) + if err != nil { + return nil, err + } + selectedUTXOs, err := s.selectExternalSpendableUTXOs(externalUTXOs, request.Address) + if err != nil { + return nil, err + } + return &pb.GetExternalSpendableUTXOsResponse{ + Entries: selectedUTXOs, + }, nil +} + +func (s *server) selectExternalSpendableUTXOs(externalUTXOs *appmessage.GetUTXOsByAddressesResponseMessage, address string) ([]*pb.UtxosByAddressesEntry, error) { + + dagInfo, err := s.rpcClient.GetBlockDAGInfo() + if err != nil { + return nil, err + } + + daaScore := dagInfo.VirtualDAAScore + maturity := s.params.BlockCoinbaseMaturity + + //we do not make because we do not know size, because of unspendable utxos + var selectedExternalUtxos []*pb.UtxosByAddressesEntry + + for _, entry := range externalUTXOs.Entries { + if !isExternalUTXOSpendable(entry, daaScore, maturity) { + continue + } + selectedExternalUtxos = append(selectedExternalUtxos, libkaspawallet.AppMessageUTXOToKaspawalletdUTXO(entry)) + } + + return selectedExternalUtxos, nil +} + +func isExternalUTXOSpendable(entry *appmessage.UTXOsByAddressesEntry, virtualDAAScore uint64, coinbaseMaturity uint64) bool { + if !entry.UTXOEntry.IsCoinbase { + return true + } else if entry.UTXOEntry.Amount <= feePerInput { + return false + } + return entry.UTXOEntry.BlockDAAScore+coinbaseMaturity < virtualDAAScore +} diff --git a/cmd/kaspawallet/daemon/server/send.go b/cmd/kaspawallet/daemon/server/send.go index 467b62b87..aae67a96a 100644 --- a/cmd/kaspawallet/daemon/server/send.go +++ b/cmd/kaspawallet/daemon/server/send.go @@ -16,7 +16,7 @@ func (s *server) Send(_ context.Context, request *pb.SendRequest) (*pb.SendRespo return nil, err } - txIDs, err := s.broadcast(signedTransactions) + txIDs, err := s.broadcast(signedTransactions, false) if err != nil { return nil, err } diff --git a/cmd/kaspawallet/libkaspawallet/converters.go b/cmd/kaspawallet/libkaspawallet/converters.go new file mode 100644 index 000000000..82a7cdc5e --- /dev/null +++ b/cmd/kaspawallet/libkaspawallet/converters.go @@ -0,0 +1,61 @@ +package libkaspawallet + +import ( + "encoding/hex" + + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" +) + +//KaspawalletdUTXOsTolibkaspawalletUTXOs converts a []*pb.UtxosByAddressesEntry to a []*libkaspawallet.UTXO +func KaspawalletdUTXOsTolibkaspawalletUTXOs(kaspawalletdUtxoEntires []*pb.UtxosByAddressesEntry) ([]*UTXO, error) { + UTXOs := make([]*UTXO, len(kaspawalletdUtxoEntires)) + for i, entry := range kaspawalletdUtxoEntires { + script, err := hex.DecodeString(entry.UtxoEntry.ScriptPublicKey.ScriptPublicKey) + if err != nil { + return nil, err + } + transactionID, err := transactionid.FromString(entry.Outpoint.TransactionId) + if err != nil { + return nil, err + } + UTXOs[i] = &UTXO{ + UTXOEntry: utxo.NewUTXOEntry( + entry.UtxoEntry.Amount, + &externalapi.ScriptPublicKey{ + Script: script, + Version: uint16(entry.UtxoEntry.ScriptPublicKey.Version), + }, + entry.UtxoEntry.IsCoinbase, + entry.UtxoEntry.BlockDaaScore, + ), + Outpoint: &externalapi.DomainOutpoint{ + TransactionID: *transactionID, + Index: entry.Outpoint.Index, + }, + } + } + return UTXOs, nil +} + +// AppMessageUTXOToKaspawalletdUTXO converts an appmessage.UTXOsByAddressesEntry to a pb.UtxosByAddressesEntry +func AppMessageUTXOToKaspawalletdUTXO(appUTXOsByAddressesEntry *appmessage.UTXOsByAddressesEntry) *pb.UtxosByAddressesEntry { + return &pb.UtxosByAddressesEntry{ + Outpoint: &pb.Outpoint{ + TransactionId: appUTXOsByAddressesEntry.Outpoint.TransactionID, + Index: appUTXOsByAddressesEntry.Outpoint.Index, + }, + UtxoEntry: &pb.UtxoEntry{ + Amount: appUTXOsByAddressesEntry.UTXOEntry.Amount, + ScriptPublicKey: &pb.ScriptPublicKey{ + Version: uint32(appUTXOsByAddressesEntry.UTXOEntry.ScriptPublicKey.Version), + ScriptPublicKey: appUTXOsByAddressesEntry.UTXOEntry.ScriptPublicKey.Script, + }, + BlockDaaScore: appUTXOsByAddressesEntry.UTXOEntry.BlockDAAScore, + IsCoinbase: appUTXOsByAddressesEntry.UTXOEntry.IsCoinbase, + }, + } +} diff --git a/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.pb.go b/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.pb.go index 5dc67cc97..8a34d1578 100644 --- a/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.pb.go +++ b/cmd/kaspawallet/libkaspawallet/serialization/protoserialization/wallet.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.12.3 +// protoc-gen-go v1.28.0 +// protoc v3.17.2 // source: wallet.proto package protoserialization import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type PartiallySignedTransaction struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/cmd/kaspawallet/libkaspawallet/serialization/serialization.go b/cmd/kaspawallet/libkaspawallet/serialization/serialization.go index 4abc6b5d9..f5f1cfaf4 100644 --- a/cmd/kaspawallet/libkaspawallet/serialization/serialization.go +++ b/cmd/kaspawallet/libkaspawallet/serialization/serialization.go @@ -3,11 +3,11 @@ package serialization import ( "math" - "github.com/golang/protobuf/proto" "github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet/serialization/protoserialization" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/pkg/errors" + "google.golang.org/protobuf/proto" ) // PartiallySignedTransaction is a type that is intended @@ -88,6 +88,22 @@ func SerializePartiallySignedTransaction(partiallySignedTransaction *PartiallySi return proto.Marshal(partiallySignedTransactionToProto(partiallySignedTransaction)) } +//DeserializeDomainTransaction Deserialize a Transaction to an *externalapi.DomainTransaction +func DeserializeDomainTransaction(serializedTransactionMessage []byte) (*externalapi.DomainTransaction, error) { + protoTransactionMessage := &protoserialization.TransactionMessage{} + err := proto.Unmarshal(serializedTransactionMessage, protoTransactionMessage) + if err != nil { + return nil, err + } + + return transactionFromProto(protoTransactionMessage) +} + +// SerializeDomainTransaction Serialize a *externalapi.DomainTransaction +func SerializeDomainTransaction(tx *externalapi.DomainTransaction) ([]byte, error) { + return proto.Marshal(transactionToProto(tx)) +} + func partiallySignedTransactionFromProto(protoPartiallySignedTransaction *protoserialization.PartiallySignedTransaction) (*PartiallySignedTransaction, error) { tx, err := transactionFromProto(protoPartiallySignedTransaction.Tx) if err != nil { diff --git a/cmd/kaspawallet/main.go b/cmd/kaspawallet/main.go index caad4f0e6..48995925b 100644 --- a/cmd/kaspawallet/main.go +++ b/cmd/kaspawallet/main.go @@ -29,6 +29,8 @@ func main() { err = dumpUnencryptedData(config.(*dumpUnencryptedDataConfig)) case startDaemonSubCmd: err = startDaemon(config.(*startDaemonConfig)) + case sweepSubCmd: + err = sweep(config.(*sweepConfig)) default: err = errors.Errorf("Unknown sub-command '%s'\n", subCmd) } diff --git a/cmd/kaspawallet/sweep.go b/cmd/kaspawallet/sweep.go new file mode 100644 index 000000000..d36065d05 --- /dev/null +++ b/cmd/kaspawallet/sweep.go @@ -0,0 +1,242 @@ +package main + +import ( + "context" + "encoding/hex" + "fmt" + + "github.com/kaspanet/go-secp256k1" + "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client" + "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb" + "github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet" + "github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet/serialization" + "github.com/kaspanet/kaspad/cmd/kaspawallet/utils" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/domain/miningmanager/mempool" + "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/util/txmass" + "github.com/pkg/errors" +) + +const feePerInput = 10000 + +func sweep(conf *sweepConfig) error { + + privateKeyBytes, err := hex.DecodeString(conf.PrivateKey) + if err != nil { + return err + } + + publicKeybytes, err := libkaspawallet.PublicKeyFromPrivateKey(privateKeyBytes) + if err != nil { + return err + } + + addressPubKey, err := util.NewAddressPublicKey(publicKeybytes, conf.NetParams().Prefix) + if err != nil { + return err + } + + address, err := util.DecodeAddress(addressPubKey.String(), conf.NetParams().Prefix) + if err != nil { + return err + } + + daemonClient, tearDown, err := client.Connect(conf.DaemonAddress) + if err != nil { + return err + } + defer tearDown() + + ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout) + defer cancel() + + getExternalSpendableUTXOsResponse, err := daemonClient.GetExternalSpendableUTXOs(ctx, &pb.GetExternalSpendableUTXOsRequest{ + Address: address.String(), + }) + if err != nil { + return err + } + + UTXOs, err := libkaspawallet.KaspawalletdUTXOsTolibkaspawalletUTXOs(getExternalSpendableUTXOsResponse.Entries) + if err != nil { + return err + } + + paymentAmount := uint64(0) + + if len(UTXOs) == 0 { + return errors.Errorf("Could not find any spendable UTXOs in %s", addressPubKey) + } + + for _, UTXO := range UTXOs { + paymentAmount = paymentAmount + UTXO.UTXOEntry.Amount() + } + + newAddressResponse, err := daemonClient.NewAddress(ctx, &pb.NewAddressRequest{}) + if err != nil { + return err + } + + toAddress, err := util.DecodeAddress(newAddressResponse.Address, conf.ActiveNetParams.Prefix) + if err != nil { + return err + } + + splitTransactions, err := createSplitTransactionsWithSchnorrPrivteKey(conf.NetParams(), UTXOs, toAddress, feePerInput) + if err != nil { + return err + } + + serializedSplitTransactions, err := signWithSchnorrPrivateKey(conf.NetParams(), privateKeyBytes, splitTransactions) + if err != nil { + return err + } + + fmt.Println("\nSweeping...") + fmt.Println("\tFrom:\t", addressPubKey) + fmt.Println("\tTo:\t", toAddress) + + response, err := daemonClient.Broadcast(ctx, &pb.BroadcastRequest{ + IsDomain: true, + Transactions: serializedSplitTransactions, + }) + if err != nil { + return err + } + + totalExtracted := uint64(0) + + fmt.Println("\nTransaction ID(s):") + for i, txID := range response.TxIDs { + fmt.Printf("\t%s\n", txID) + fmt.Println("\tSwept:\t", utils.FormatKas(splitTransactions[i].Outputs[0].Value), " KAS") + totalExtracted = totalExtracted + splitTransactions[i].Outputs[0].Value + } + + fmt.Println("\nTotal Funds swept (including transaction fees):") + fmt.Println("\t", utils.FormatKas(totalExtracted), " KAS") + + return nil +} + +func newDummyTransaction() *externalapi.DomainTransaction { + return &externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: make([]*externalapi.DomainTransactionInput, 0), //we create empty inputs + LockTime: 0, + Outputs: make([]*externalapi.DomainTransactionOutput, 1), // we should always have 1 output to the toAdress + SubnetworkID: subnetworks.SubnetworkIDNative, + Gas: 0, + Payload: nil, + } +} + +func createSplitTransactionsWithSchnorrPrivteKey( + params *dagconfig.Params, + selectedUTXOs []*libkaspawallet.UTXO, + toAddress util.Address, + feePerInput int) ([]*externalapi.DomainTransaction, error) { + + var splitTransactions []*externalapi.DomainTransaction + + extraMass := uint64(7000) // Account for future signatures. + + massCalculater := txmass.NewCalculator(params.MassPerTxByte, params.MassPerScriptPubKeyByte, params.MassPerSigOp) + + scriptPublicKey, err := txscript.PayToAddrScript(toAddress) + if err != nil { + return nil, err + } + + totalSplitAmount := uint64(0) + + lastValidTx := newDummyTransaction() + currentTx := newDummyTransaction() //i.e. the tested tx + + //loop through utxos commit segments that don't violate max mass + for i, currentUTXO := range selectedUTXOs { + + totalSplitAmount = totalSplitAmount + currentUTXO.UTXOEntry.Amount() + + currentTx.Inputs = append( + currentTx.Inputs, + &externalapi.DomainTransactionInput{ + PreviousOutpoint: *currentUTXO.Outpoint, + UTXOEntry: utxo.NewUTXOEntry( + currentUTXO.UTXOEntry.Amount(), + currentUTXO.UTXOEntry.ScriptPublicKey(), + false, + constants.UnacceptedDAAScore, + ), + SigOpCount: 1, + }, + ) + + currentTx.Outputs[0] = &externalapi.DomainTransactionOutput{ + Value: totalSplitAmount - uint64(len(currentTx.Inputs)*feePerInput), + ScriptPublicKey: scriptPublicKey, + } + + if massCalculater.CalculateTransactionMass(currentTx)+extraMass >= mempool.MaximumStandardTransactionMass { + + //in this loop we assume a transaction with one input and one output cannot violate max transaction mass, hence a sanity check. + if len(currentTx.Inputs) == 1 { + return nil, errors.Errorf("transaction with one input and one output violates transaction mass") + } + + splitTransactions = append(splitTransactions, lastValidTx) + totalSplitAmount = 0 + lastValidTx = newDummyTransaction() + currentTx = newDummyTransaction() + continue + } + + //Special case, end of inputs, with no violation, where we can assign currentTX to split and break + if i == len(selectedUTXOs)-1 { + splitTransactions = append(splitTransactions, currentTx) + break + + } + + lastValidTx = currentTx.Clone() + currentTx.Outputs = make([]*externalapi.DomainTransactionOutput, 1) + + } + return splitTransactions, nil +} + +func signWithSchnorrPrivateKey(params *dagconfig.Params, privateKeyBytes []byte, domainTransactions []*externalapi.DomainTransaction) ([][]byte, error) { + + schnorrkeyPair, err := secp256k1.DeserializeSchnorrPrivateKeyFromSlice(privateKeyBytes) + if err != nil { + return nil, err + } + + serializedDomainTransactions := make([][]byte, len(domainTransactions)) + + for i1, domainTransaction := range domainTransactions { + + sighashReusedValues := &consensushashing.SighashReusedValues{} + + for i2, input := range domainTransaction.Inputs { + signature, err := txscript.SignatureScript(domainTransaction, i2, consensushashing.SigHashAll, schnorrkeyPair, sighashReusedValues) + if err != nil { + return nil, err + } + input.SignatureScript = signature + } + serializedDomainTransactions[i1], err = serialization.SerializeDomainTransaction(domainTransaction) + if err != nil { + return nil, err + } + } + + return serializedDomainTransactions, nil +} diff --git a/cmd/kaspawallet/utils/format_kas.go b/cmd/kaspawallet/utils/format_kas.go new file mode 100644 index 000000000..5b1de0bea --- /dev/null +++ b/cmd/kaspawallet/utils/format_kas.go @@ -0,0 +1,16 @@ +package utils + +import ( + "fmt" + + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" +) + +// FormatKas takes the amount of sompis as uint64, and returns amount of KAS with 8 decimal places +func FormatKas(amount uint64) string { + res := " " + if amount > 0 { + res = fmt.Sprintf("%19.8f", float64(amount)/constants.SompiPerKaspa) + } + return res +} diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index 931fb0ac5..f237621c3 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.12.3 +// protoc-gen-go v1.28.0 +// protoc v3.17.2 // source: dbobjects.proto package serialization import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type DbBlock struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/infrastructure/network/dnsseed/pb/peer_service.pb.go b/infrastructure/network/dnsseed/pb/peer_service.pb.go index 3ddaa095f..778616cf8 100644 --- a/infrastructure/network/dnsseed/pb/peer_service.pb.go +++ b/infrastructure/network/dnsseed/pb/peer_service.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.12.3 +// protoc-gen-go v1.28.0 +// protoc v3.17.2 // source: peer_service.proto package pb import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type GetPeersListRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/infrastructure/network/dnsseed/pb/peer_service_grpc.pb.go b/infrastructure/network/dnsseed/pb/peer_service_grpc.pb.go index 975d57909..ac7af9e3f 100644 --- a/infrastructure/network/dnsseed/pb/peer_service_grpc.pb.go +++ b/infrastructure/network/dnsseed/pb/peer_service_grpc.pb.go @@ -1,4 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.17.2 +// source: peer_service.proto package pb @@ -11,7 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 // PeerServiceClient is the client API for PeerService service. // @@ -49,13 +54,20 @@ type PeerServiceServer interface { type UnimplementedPeerServiceServer struct { } -func (*UnimplementedPeerServiceServer) GetPeersList(context.Context, *GetPeersListRequest) (*GetPeersListResponse, error) { +func (UnimplementedPeerServiceServer) GetPeersList(context.Context, *GetPeersListRequest) (*GetPeersListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetPeersList not implemented") } -func (*UnimplementedPeerServiceServer) mustEmbedUnimplementedPeerServiceServer() {} +func (UnimplementedPeerServiceServer) mustEmbedUnimplementedPeerServiceServer() {} -func RegisterPeerServiceServer(s *grpc.Server, srv PeerServiceServer) { - s.RegisterService(&_PeerService_serviceDesc, srv) +// UnsafePeerServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PeerServiceServer will +// result in compilation errors. +type UnsafePeerServiceServer interface { + mustEmbedUnimplementedPeerServiceServer() +} + +func RegisterPeerServiceServer(s grpc.ServiceRegistrar, srv PeerServiceServer) { + s.RegisterService(&PeerService_ServiceDesc, srv) } func _PeerService_GetPeersList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { @@ -76,7 +88,10 @@ func _PeerService_GetPeersList_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } -var _PeerService_serviceDesc = grpc.ServiceDesc{ +// PeerService_ServiceDesc is the grpc.ServiceDesc for PeerService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PeerService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "PeerService", HandlerType: (*PeerServiceServer)(nil), Methods: []grpc.MethodDesc{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 221e8e687..588cdb24f 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.12.3 +// protoc-gen-go v1.28.0 +// protoc v3.17.2 // source: messages.proto package protowire import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type KaspadMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go index 102e61cfd..926b6ff3a 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go @@ -1,4 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.17.2 +// source: messages.proto package protowire @@ -11,7 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 // P2PClient is the client API for P2P service. // @@ -29,7 +34,7 @@ func NewP2PClient(cc grpc.ClientConnInterface) P2PClient { } func (c *p2PClient) MessageStream(ctx context.Context, opts ...grpc.CallOption) (P2P_MessageStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &_P2P_serviceDesc.Streams[0], "/protowire.P2P/MessageStream", opts...) + stream, err := c.cc.NewStream(ctx, &P2P_ServiceDesc.Streams[0], "/protowire.P2P/MessageStream", opts...) if err != nil { return nil, err } @@ -71,13 +76,20 @@ type P2PServer interface { type UnimplementedP2PServer struct { } -func (*UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error { +func (UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error { return status.Errorf(codes.Unimplemented, "method MessageStream not implemented") } -func (*UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {} +func (UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {} -func RegisterP2PServer(s *grpc.Server, srv P2PServer) { - s.RegisterService(&_P2P_serviceDesc, srv) +// UnsafeP2PServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to P2PServer will +// result in compilation errors. +type UnsafeP2PServer interface { + mustEmbedUnimplementedP2PServer() +} + +func RegisterP2PServer(s grpc.ServiceRegistrar, srv P2PServer) { + s.RegisterService(&P2P_ServiceDesc, srv) } func _P2P_MessageStream_Handler(srv interface{}, stream grpc.ServerStream) error { @@ -106,7 +118,10 @@ func (x *p2PMessageStreamServer) Recv() (*KaspadMessage, error) { return m, nil } -var _P2P_serviceDesc = grpc.ServiceDesc{ +// P2P_ServiceDesc is the grpc.ServiceDesc for P2P service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var P2P_ServiceDesc = grpc.ServiceDesc{ ServiceName: "protowire.P2P", HandlerType: (*P2PServer)(nil), Methods: []grpc.MethodDesc{}, @@ -137,7 +152,7 @@ func NewRPCClient(cc grpc.ClientConnInterface) RPCClient { } func (c *rPCClient) MessageStream(ctx context.Context, opts ...grpc.CallOption) (RPC_MessageStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &_RPC_serviceDesc.Streams[0], "/protowire.RPC/MessageStream", opts...) + stream, err := c.cc.NewStream(ctx, &RPC_ServiceDesc.Streams[0], "/protowire.RPC/MessageStream", opts...) if err != nil { return nil, err } @@ -179,13 +194,20 @@ type RPCServer interface { type UnimplementedRPCServer struct { } -func (*UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error { +func (UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error { return status.Errorf(codes.Unimplemented, "method MessageStream not implemented") } -func (*UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {} +func (UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {} -func RegisterRPCServer(s *grpc.Server, srv RPCServer) { - s.RegisterService(&_RPC_serviceDesc, srv) +// UnsafeRPCServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to RPCServer will +// result in compilation errors. +type UnsafeRPCServer interface { + mustEmbedUnimplementedRPCServer() +} + +func RegisterRPCServer(s grpc.ServiceRegistrar, srv RPCServer) { + s.RegisterService(&RPC_ServiceDesc, srv) } func _RPC_MessageStream_Handler(srv interface{}, stream grpc.ServerStream) error { @@ -214,7 +236,10 @@ func (x *rPCMessageStreamServer) Recv() (*KaspadMessage, error) { return m, nil } -var _RPC_serviceDesc = grpc.ServiceDesc{ +// RPC_ServiceDesc is the grpc.ServiceDesc for RPC service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var RPC_ServiceDesc = grpc.ServiceDesc{ ServiceName: "protowire.RPC", HandlerType: (*RPCServer)(nil), Methods: []grpc.MethodDesc{}, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go index 5b6773f3c..334ebda4c 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.12.3 +// protoc-gen-go v1.28.0 +// protoc v3.17.2 // source: p2p.proto package protowire import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type RequestAddressesMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index 409bc9f6f..36763ae5e 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -10,14 +10,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.12.3 +// protoc-gen-go v1.28.0 +// protoc v3.17.2 // source: rpc.proto package protowire import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -31,10 +30,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type SubmitBlockResponseMessage_RejectReason int32 const (