diff --git a/Package.resolved b/Package.resolved index 1c1a80f0..68f9ccfa 100644 --- a/Package.resolved +++ b/Package.resolved @@ -239,8 +239,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "3c54ab05249f59f2c6641dd2920b8358ea9ed127", - "version" : "1.24.0" + "revision" : "e17d61f26df0f0e06f58f6977ba05a097a720106", + "version" : "1.27.1" } }, { diff --git a/Package.swift b/Package.swift index 4e5ccdfd..ae22bc09 100644 --- a/Package.swift +++ b/Package.swift @@ -88,7 +88,7 @@ let package = Package( .package(url: "https://github.com/objecthub/swift-numberkit.git", from: "2.4.1"), .package(url: "https://github.com/thebarndog/swift-dotenv.git", from: "1.0.0"), .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.23.0"), - .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.6.0"), + .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0"), .package(url: "https://github.com/vsanthanam/AnyAsyncSequence.git", from: "1.0.0"), .package(url: "https://github.com/apple/swift-atomics.git", from: "1.1.0"), // swift-asn1 wants swift 5.7+ past 0.4 diff --git a/Sources/Hedera/AddressBook/NodeCreateTransaction.swift b/Sources/Hedera/AddressBook/NodeCreateTransaction.swift new file mode 100644 index 00000000..b01f7ba9 --- /dev/null +++ b/Sources/Hedera/AddressBook/NodeCreateTransaction.swift @@ -0,0 +1,242 @@ +/* + * ‌ + * Hedera Swift SDK + * ​ + * Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +import Foundation +import GRPC +import HederaProtobufs +import SwiftProtobuf + +/// A transaction body to add a new consensus node to the network address book. +/// +/// This transaction body SHALL be considered a "privileged transaction". +/// +/// This message supports a transaction to create a new node in the network +/// address book. The transaction, once complete, enables a new consensus node +/// to join the network, and requires governing council authorization. +/// +/// - A `NodeCreateTransactionBody` MUST be signed by the governing council. +/// - A `NodeCreateTransactionBody` MUST be signed by the `Key` assigned to the +/// `admin_key` field. +/// - The newly created node information SHALL be added to the network address +/// book information in the network state. +/// - The new entry SHALL be created in "state" but SHALL NOT participate in +/// network consensus and SHALL NOT be present in network "configuration" +/// until the next "upgrade" transaction (as noted below). +/// - All new address book entries SHALL be added to the active network +/// configuration during the next `freeze` transaction with the field +/// `freeze_type` set to `PREPARE_UPGRADE`. +/// +public final class NodeCreateTransaction: Transaction { + public init( + accountId: AccountId? = nil, + description: String = "", + gossipEndpoints: [Endpoint] = [], + serviceEndpoints: [Endpoint] = [], + gossipCaCertificate: Data? = nil, + grpcCertificateHash: Data? = nil, + adminKey: Key? = nil + ) { + self.accountId = accountId + self.description = description + self.gossipEndpoints = gossipEndpoints + self.serviceEndpoints = serviceEndpoints + self.gossipCaCertificate = gossipCaCertificate + self.grpcCertificateHash = grpcCertificateHash + self.adminKey = adminKey + + super.init() + } + + internal init( + protobuf proto: Proto_TransactionBody, _ data: Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody + ) throws { + self.accountId = data.hasAccountID ? try .fromProtobuf(data.accountID) : nil + self.description = data.description_p + self.gossipEndpoints = try data.gossipEndpoint.map(Endpoint.init) + self.serviceEndpoints = try data.serviceEndpoint.map(Endpoint.init) + self.gossipCaCertificate = data.gossipCaCertificate + self.grpcCertificateHash = data.grpcCertificateHash + self.adminKey = data.hasAdminKey ? try .fromProtobuf(data.adminKey) : nil + + try super.init(protobuf: proto) + } + + /// Node account ID. + public var accountId: AccountId? { + willSet { + ensureNotFrozen() + } + } + + /// Sets the node account + @discardableResult + public func accountId(_ accountId: AccountId?) -> Self { + self.accountId = accountId + + return self + } + + /// Returns the nodes description. + public var description: String { + willSet { + ensureNotFrozen() + } + } + + /// Sets the node's description. + @discardableResult + public func description(_ description: String) -> Self { + self.description = description + + return self + } + + /// A list of service endpoints for gossip. + public var gossipEndpoints: [Endpoint] { + willSet { + ensureNotFrozen() + } + } + + /// Assign the list of service endpoints for gossip. + @discardableResult + public func gossipEndpoints(_ gossipEndpoints: [Endpoint]) -> Self { + self.gossipEndpoints = gossipEndpoints + + return self + } + + /// Add an endpoint for gossip to the list of service endpoints for gossip. + @discardableResult + public func addGossipEndpoint(_ gossipEndpoint: Endpoint) -> Self { + self.gossipEndpoints.append(gossipEndpoint) + + return self + } + + /// Extract the list of service endpoints for gRPC calls. + public var serviceEndpoints: [Endpoint] { + willSet { + ensureNotFrozen() + } + } + + /// Assign the list of service endpoints for gRPC calls. + @discardableResult + public func serviceEndpoints(_ serviceEndpoints: [Endpoint]) -> Self { + self.serviceEndpoints = serviceEndpoints + + return self + } + + /// Add an endpoint for gRPC calls to the list of service endpoints for gRPC calls. + @discardableResult + public func addServiceEndpoint(_ serviceEndpoint: Endpoint) -> Self { + self.serviceEndpoints.append(serviceEndpoint) + + return self + } + + /// Extract the certificate used to sign gossip events. + public var gossipCaCertificate: Data? { + willSet { + ensureNotFrozen() + } + } + + /// Sets the certificate used to sign gossip events. + @discardableResult + public func gossipCaCertificate(_ gossipCaCertificate: Data) -> Self { + self.gossipCaCertificate = gossipCaCertificate + + return self + } + + /// Extract the hash of the node gRPC TLS certificate. + public var grpcCertificateHash: Data? { + willSet { + ensureNotFrozen() + } + } + + /// Sets the hash of the node gRPC TLS certificate. + @discardableResult + public func grpcCertificateHash(_ grpcCertificateHash: Data) -> Self { + self.grpcCertificateHash = grpcCertificateHash + + return self + } + + /// Get an administrative key controlled by the node operator. + public var adminKey: Key? { + willSet { + ensureNotFrozen() + } + } + + /// Sets an administrative key controlled by the node operator. + @discardableResult + public func adminKey(_ adminKey: Key) -> Self { + self.adminKey = adminKey + + return self + } + + internal override func validateChecksums(on ledgerId: LedgerId) throws { + try accountId?.validateChecksums(on: ledgerId) + try super.validateChecksums(on: ledgerId) + } + + internal override func transactionExecute(_ channel: GRPCChannel, _ request: Proto_Transaction) async throws + -> Proto_TransactionResponse + { + try await Proto_AddressBookServiceAsyncClient(channel: channel).createNode(request) + } + + internal override func toTransactionDataProtobuf(_ chunkInfo: ChunkInfo) -> Proto_TransactionBody.OneOf_Data { + _ = chunkInfo.assertSingleTransaction() + + return .nodeCreate(toProtobuf()) + } +} + +extension NodeCreateTransaction: ToProtobuf { + internal typealias Protobuf = Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody + + internal func toProtobuf() -> Protobuf { + .with { proto in + accountId?.toProtobufInto(&proto.accountID) + proto.description_p = description + proto.gossipEndpoint = gossipEndpoints.map { $0.toProtobuf() } + proto.serviceEndpoint = serviceEndpoints.map { $0.toProtobuf() } + proto.gossipCaCertificate = gossipCaCertificate ?? Data() + proto.grpcCertificateHash = grpcCertificateHash ?? Data() + if let adminKey = adminKey { + proto.adminKey = adminKey.toProtobuf() + } + } + } +} + +extension NodeCreateTransaction { + internal func toSchedulableTransactionData() -> Proto_SchedulableTransactionBody.OneOf_Data { + .nodeCreate(toProtobuf()) + } +} diff --git a/Sources/Hedera/AddressBook/NodeDeleteTransaction.swift b/Sources/Hedera/AddressBook/NodeDeleteTransaction.swift new file mode 100644 index 00000000..c26a85a4 --- /dev/null +++ b/Sources/Hedera/AddressBook/NodeDeleteTransaction.swift @@ -0,0 +1,98 @@ +/* + * ‌ + * Hedera Swift SDK + * ​ + * Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +import Foundation +import GRPC +import HederaProtobufs +import SwiftProtobuf + +/// A transaction body to delete a node from the network address book. +/// +/// This transaction body SHALL be considered a "privileged transaction". +/// +/// - A `NodeDeleteTransactionBody` MUST be signed by the governing council. +/// - Upon success, the address book entry SHALL enter a "pending delete" +/// state. +/// - All address book entries pending deletion SHALL be removed from the +/// active network configuration during the next `freeze` transaction with +/// the field `freeze_type` set to `PREPARE_UPGRADE`.
+/// - A deleted address book node SHALL be removed entirely from network state. +/// - A deleted address book node identifier SHALL NOT be reused. +public final class NodeDeleteTransaction: Transaction { + public init( + nodeId: UInt64 = 0 + ) { + self.nodeId = nodeId + super.init() + } + + internal init( + protobuf proto: Proto_TransactionBody, _ data: Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody + ) throws { + self.nodeId = data.nodeID + + try super.init(protobuf: proto) + } + + /// Node index to delete. + public var nodeId: UInt64 { + willSet { + ensureNotFrozen() + } + } + + /// Sets the node index to delete. + @discardableResult + public func nodeId(_ nodeId: UInt64) -> Self { + self.nodeId = nodeId + + return self + } + + internal override func validateChecksums(on ledgerId: LedgerId) throws {} + + internal override func transactionExecute(_ channel: GRPCChannel, _ request: Proto_Transaction) async throws + -> Proto_TransactionResponse + { + try await Proto_AddressBookServiceAsyncClient(channel: channel).deleteNode(request) + } + + internal override func toTransactionDataProtobuf(_ chunkInfo: ChunkInfo) -> Proto_TransactionBody.OneOf_Data { + _ = chunkInfo.assertSingleTransaction() + + return .nodeDelete(toProtobuf()) + } +} + +extension NodeDeleteTransaction: ToProtobuf { + internal typealias Protobuf = Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody + + internal func toProtobuf() -> Protobuf { + .with { proto in + proto.nodeID = nodeId + } + } +} + +extension NodeDeleteTransaction { + internal func toSchedulableTransactionData() -> Proto_SchedulableTransactionBody.OneOf_Data { + .nodeDelete(toProtobuf()) + } +} diff --git a/Sources/Hedera/AddressBook/NodeUpdateTransaction.swift b/Sources/Hedera/AddressBook/NodeUpdateTransaction.swift new file mode 100644 index 00000000..0c7e2a9f --- /dev/null +++ b/Sources/Hedera/AddressBook/NodeUpdateTransaction.swift @@ -0,0 +1,259 @@ +/* + * ‌ + * Hedera Swift SDK + * ​ + * Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +import Foundation +import GRPC +import HederaProtobufs +import SwiftProtobuf + +/// Transaction body to modify address book node attributes. +/// +/// - This transaction SHALL enable the node operator, as identified by the +/// `admin_key`, to modify operational attributes of the node. +/// - This transaction MUST be signed by the active `admin_key` for the node. +/// - If this transaction sets a new value for the `admin_key`, then both the +/// current `admin_key`, and the new `admin_key` MUST sign this transaction. +/// - This transaction SHALL NOT change any field that is not set (is null) in +/// this transaction body. +/// - This SHALL create a pending update to the node, but the change SHALL NOT +/// be immediately applied to the active configuration. +/// - All pending node updates SHALL be applied to the active network +/// configuration during the next `freeze` transaction with the field +/// `freeze_type` set to `PREPARE_UPGRADE`. +public final class NodeUpdateTransaction: Transaction { + public init( + nodeId: UInt64 = 0, + accountId: AccountId? = nil, + description: String? = nil, + gossipEndpoints: [Endpoint] = [], + serviceEndpoints: [Endpoint] = [], + gossipCaCertificate: Data? = nil, + grpcCertificateHash: Data? = nil, + adminKey: Key? = nil + ) { + self.nodeId = nodeId + self.accountId = accountId + self.description = description + self.gossipEndpoints = gossipEndpoints + self.serviceEndpoints = serviceEndpoints + self.gossipCaCertificate = gossipCaCertificate + self.grpcCertificateHash = grpcCertificateHash + self.adminKey = adminKey + + super.init() + } + + internal init( + protobuf proto: Proto_TransactionBody, _ data: Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody + ) throws { + self.nodeId = data.nodeID + self.accountId = data.hasAccountID ? try .fromProtobuf(data.accountID) : nil + self.description = data.hasDescription_p ? data.description_p.value : nil + self.gossipEndpoints = try data.gossipEndpoint.map(Endpoint.init) + self.serviceEndpoints = try data.serviceEndpoint.map(Endpoint.init) + self.gossipCaCertificate = data.hasGossipCaCertificate ? data.gossipCaCertificate.value : nil + self.grpcCertificateHash = data.hasGrpcCertificateHash ? data.grpcCertificateHash.value : nil + self.adminKey = data.hasAdminKey ? try .fromProtobuf(data.adminKey) : nil + + try super.init(protobuf: proto) + } + + /// Node index to update. + public var nodeId: UInt64? { + willSet { + ensureNotFrozen() + } + } + + /// Sets the node index to update. + @discardableResult + public func nodeId(_ nodeId: UInt64) -> Self { + self.nodeId = nodeId + + return self + } + + /// Node account ID. + public var accountId: AccountId? { + willSet { + ensureNotFrozen() + } + } + + /// Sets the node account Id. + @discardableResult + public func accountId(_ accountId: AccountId) -> Self { + self.accountId = accountId + + return self + } + + /// Returns the updated node description. + public var description: String? { + willSet { + ensureNotFrozen() + } + } + + /// Sets the node's description. + @discardableResult + public func description(_ description: String) -> Self { + self.description = description + + return self + } + + /// A list of service endpoints for gossip. + public var gossipEndpoints: [Endpoint] { + willSet { + ensureNotFrozen() + } + } + + /// Assign the list of service endpoints for gossip. + @discardableResult + public func gossipEndpoints(_ gossipEndpoints: [Endpoint]) -> Self { + self.gossipEndpoints = gossipEndpoints + + return self + } + + /// Add an endpoint for gossip to the list of service endpoints for gossip. + @discardableResult + public func addGossipEndpoint(_ gossipEndpoint: Endpoint) -> Self { + self.gossipEndpoints.append(gossipEndpoint) + + return self + } + + /// Extract the list of service endpoints for gRPC calls. + public var serviceEndpoints: [Endpoint] { + willSet { + ensureNotFrozen() + } + } + + /// Assign the list of service endpoints for gRPC calls. + @discardableResult + public func serviceEndpoints(_ serviceEndpoints: [Endpoint]) -> Self { + self.serviceEndpoints = serviceEndpoints + + return self + } + + /// Add an endpoint for gRPC calls to the list of service endpoints for gRPC calls. + @discardableResult + public func addServiceEndpoint(_ serviceEndpoint: Endpoint) -> Self { + self.serviceEndpoints.append(serviceEndpoint) + + return self + } + + /// Extract the certificate used to sign gossip events. + public var gossipCaCertificate: Data? { + willSet { + ensureNotFrozen() + } + } + + /// Sets the certificate used to sign gossip events. + @discardableResult + public func gossipCaCertificate(_ gossipCaCertificate: Data) -> Self { + self.gossipCaCertificate = gossipCaCertificate + + return self + } + + /// Extract the hash of the node gRPC TLS certificate. + public var grpcCertificateHash: Data? { + willSet { + ensureNotFrozen() + } + } + + /// Sets the hash of the node gRPC TLS certificate. + @discardableResult + public func grpcCertificateHash(_ grpcCertificateHash: Data) -> Self { + self.grpcCertificateHash = grpcCertificateHash + + return self + } + + /// Get an administrative key controlled by the node operator. + public var adminKey: Key? { + willSet { + ensureNotFrozen() + } + } + + /// Sets an administrative key controlled by the node operator. + @discardableResult + public func adminKey(_ adminKey: Key) -> Self { + self.adminKey = adminKey + + return self + } + + internal override func validateChecksums(on ledgerId: LedgerId) throws { + try accountId?.validateChecksums(on: ledgerId) + try super.validateChecksums(on: ledgerId) + } + + internal override func transactionExecute(_ channel: GRPCChannel, _ request: Proto_Transaction) async throws + -> Proto_TransactionResponse + { + try await Proto_AddressBookServiceAsyncClient(channel: channel).updateNode(request) + } + + internal override func toTransactionDataProtobuf(_ chunkInfo: ChunkInfo) -> Proto_TransactionBody.OneOf_Data { + _ = chunkInfo.assertSingleTransaction() + + return .nodeUpdate(toProtobuf()) + } +} + +extension NodeUpdateTransaction: ToProtobuf { + internal typealias Protobuf = Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody + + internal func toProtobuf() -> Protobuf { + .with { proto in + proto.nodeID = nodeId ?? 0 + accountId?.toProtobufInto(&proto.accountID) + proto.gossipEndpoint = gossipEndpoints.map { $0.toProtobuf() } + proto.serviceEndpoint = serviceEndpoints.map { $0.toProtobuf() } + proto.gossipCaCertificate = Google_Protobuf_BytesValue(gossipCaCertificate ?? Data()) + proto.grpcCertificateHash = Google_Protobuf_BytesValue(grpcCertificateHash ?? Data()) + + if let description = description { + proto.description_p = Google_Protobuf_StringValue(description) + } + + if let adminKey = adminKey { + proto.adminKey = adminKey.toProtobuf() + } + } + } +} + +extension NodeUpdateTransaction { + internal func toSchedulableTransactionData() -> Proto_SchedulableTransactionBody.OneOf_Data { + .nodeUpdate(toProtobuf()) + } +} diff --git a/Sources/Hedera/AnyTransaction.swift b/Sources/Hedera/AnyTransaction.swift index 5e9c617d..78f80ab5 100644 --- a/Sources/Hedera/AnyTransaction.swift +++ b/Sources/Hedera/AnyTransaction.swift @@ -65,6 +65,9 @@ internal enum ServicesTransactionDataList { case ethereum([Proto_EthereumTransactionBody]) case prng([Proto_UtilPrngTransactionBody]) case tokenUpdateNfts([Proto_TokenUpdateNftsTransactionBody]) + case nodeCreate([Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody]) + case nodeUpdate([Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody]) + case nodeDelete([Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody]) internal mutating func append(_ transaction: Proto_TransactionBody.OneOf_Data) throws { switch (self, transaction) { @@ -240,6 +243,18 @@ internal enum ServicesTransactionDataList { array.append(data) self = .tokenReject(array) + case (.nodeCreate(var array), .nodeCreate(let data)): + array.append(data) + self = .nodeCreate(array) + + case (.nodeUpdate(var array), .nodeUpdate(let data)): + array.append(data) + self = .nodeUpdate(array) + + case (.nodeDelete(var array), .nodeDelete(let data)): + array.append(data) + self = .nodeDelete(array) + default: throw HError.fromProtobuf("mismatched transaction types") } @@ -304,10 +319,13 @@ extension ServicesTransactionDataList: TryFromProtobuf { case .cryptoDeleteLiveHash: throw HError.fromProtobuf("Unsupported transaction `DeleteLiveHashTransaction`") case .uncheckedSubmit: throw HError.fromProtobuf("Unsupported transaction `UncheckedSubmitTransaction`") case .nodeStakeUpdate: throw HError.fromProtobuf("Unsupported transaction `NodeStakeUpdateTransaction`") - case .nodeDelete: throw HError.fromProtobuf("Unsupported transaction `NodeDeleteTransaction`") - case .nodeCreate: throw HError.fromProtobuf("Unsupported transaction `NodeCreateTransaction`") - case .nodeUpdate: throw HError.fromProtobuf("Unsupported transaction `NodeUpdateTransaction`") + case .nodeCreate(let data): value = .nodeCreate([data]) + case .nodeUpdate(let data): value = .nodeUpdate([data]) + case .nodeDelete(let data): value = .nodeDelete([data]) case .tokenReject(let data): value = .tokenReject([data]) + case .tokenAirdrop: throw HError.fromProtobuf("Unsupported transaction `TokenAirdropTransaction`") + case .tokenCancelAirdrop: throw HError.fromProtobuf("Unsupported transaction `TokenCancelAirdropTransaction`") + case .tokenClaimAirdrop: throw HError.fromProtobuf("Unsupported transaction `TokenClaimAirdropTransaction`") } for transaction in iter { diff --git a/Sources/Hedera/Endpoint.swift b/Sources/Hedera/Endpoint.swift new file mode 100644 index 00000000..f47422e8 --- /dev/null +++ b/Sources/Hedera/Endpoint.swift @@ -0,0 +1,96 @@ +/* + * ‌ + * Hedera Swift SDK + * ​ + * Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +import Foundation +import HederaProtobufs +import Network + +public struct Endpoint { + public var ipAddress: IPv4Address? = nil + + public var port: Int32 = 0 + + public var domainName: String = "" + + public init(ipAddress: IPv4Address? = nil, port: Int32 = 0, domainName: String = "") { + self.ipAddress = ipAddress + self.port = port + self.domainName = domainName + } + + @discardableResult + public mutating func address(_ ipAddress: IPv4Address) -> Self { + self.ipAddress = ipAddress + return self + } + + @discardableResult + public mutating func port(_ port: Int32) -> Self { + self.port = port + return self + } + + @discardableResult + public mutating func domainName(_ domainName: String) -> Self { + self.domainName = domainName + return self + } + + public var description: String { + guard !domainName.isEmpty else { + return "\(ipAddress.debugDescription):\(port)" + } + return "\(domainName):\(port)" + } +} +extension Endpoint: TryProtobufCodable { + internal typealias Protobuf = Proto_ServiceEndpoint + + internal init(protobuf proto: Protobuf) throws { + let ipAddress = IPv4Address(proto.ipAddressV4) + + var port = proto.port + + if proto.port == 0 || proto.port == 50111 { + port = 50211 + } + + guard isValidDomainName(proto.domainName) else { + throw HError(kind: .basicParse, description: "Invalid domain name format") + } + + self.init(ipAddress: ipAddress, port: port, domainName: proto.domainName) + } + + internal func toProtobuf() -> Protobuf { + .with { proto in + proto.ipAddressV4 = ipAddress?.rawValue ?? Data() + proto.port = port + proto.domainName = domainName + } + } +} + +private func isValidDomainName(_ domainName: String) -> Bool { + let pattern = "^((?!-)[A-Za-z0-9-]{1,63}(?(parsing description: S) throws { @@ -58,6 +60,7 @@ public struct SocketAddressV4: LosslessStringConvertible { self.ip = ipAddress self.port = port + self.domainName = "" } public init?(_ description: String) { @@ -80,6 +83,7 @@ extension SocketAddressV4: TryProtobufCodable { .with { proto in proto.ipAddressV4 = ip.rawValue proto.port = Int32(port) + proto.domainName = domainName } } } diff --git a/Sources/Hedera/Protobufs/FromProtobuf.swift b/Sources/Hedera/Protobufs/FromProtobuf.swift index 48a6d124..e19bb214 100644 --- a/Sources/Hedera/Protobufs/FromProtobuf.swift +++ b/Sources/Hedera/Protobufs/FromProtobuf.swift @@ -16,7 +16,7 @@ extension TryFromProtobuf { internal init(protobufBytes bytes: Data) throws where Protobuf: SwiftProtobuf.Message { let protobuf: Protobuf do { - protobuf = try Protobuf(contiguousBytes: bytes) + protobuf = try Protobuf(serializedBytes: bytes) } catch { throw HError.fromProtobuf("error decoding protobuf bytes: \(error)") } diff --git a/Sources/Hedera/Schedule/ScheduleInfo.swift b/Sources/Hedera/Schedule/ScheduleInfo.swift index 5278ceb8..e9c361bd 100644 --- a/Sources/Hedera/Schedule/ScheduleInfo.swift +++ b/Sources/Hedera/Schedule/ScheduleInfo.swift @@ -116,6 +116,9 @@ public struct ScheduleInfo: Sendable { case .nodeUpdate(let data): proto.data = .nodeUpdate(data) case .nodeDelete(let data): proto.data = .nodeDelete(data) case .tokenReject(let data): proto.data = .tokenReject(data) + case .tokenAirdrop(let data): proto.data = .tokenAirdrop(data) + case .tokenCancelAirdrop(let data): proto.data = .tokenCancelAirdrop(data) + case .tokenClaimAirdrop(let data): proto.data = .tokenClaimAirdrop(data) case nil: break } diff --git a/Sources/Hedera/Token/TokenRejectTransaction.swift b/Sources/Hedera/Token/TokenRejectTransaction.swift index 641e31b0..a3cd2bcc 100644 --- a/Sources/Hedera/Token/TokenRejectTransaction.swift +++ b/Sources/Hedera/Token/TokenRejectTransaction.swift @@ -120,7 +120,7 @@ public final class TokenRejectTransaction: Transaction { internal override func transactionExecute(_ channel: GRPCChannel, _ request: Proto_Transaction) async throws -> Proto_TransactionResponse { - try await Proto_TokenServiceAsyncClient(channel: channel).deleteToken(request) + try await Proto_TokenServiceAsyncClient(channel: channel).rejectToken(request) } internal override func toTransactionDataProtobuf(_ chunkInfo: ChunkInfo) -> Proto_TransactionBody.OneOf_Data { diff --git a/Sources/Hedera/Transaction.swift b/Sources/Hedera/Transaction.swift index d5cb5102..25083d7e 100644 --- a/Sources/Hedera/Transaction.swift +++ b/Sources/Hedera/Transaction.swift @@ -360,10 +360,10 @@ public class Transaction: ValidateChecksums { public static func fromBytes(_ bytes: Data) throws -> Transaction { let list: [Proto_Transaction] do { - let tmp = try Proto_TransactionList(contiguousBytes: bytes) + let tmp = try Proto_TransactionList(serializedBytes: bytes) if tmp.transactionList.isEmpty { - list = [try Proto_Transaction(contiguousBytes: bytes)] + list = [try Proto_Transaction(serializedBytes: bytes)] } else { list = tmp.transactionList } @@ -375,7 +375,7 @@ public class Transaction: ValidateChecksums { let transactionBodies = try sources.signedTransactions.map { signed -> Proto_TransactionBody in do { - return try Proto_TransactionBody(contiguousBytes: signed.bodyBytes) + return try Proto_TransactionBody(serializedBytes: signed.bodyBytes) } catch { throw HError.fromProtobuf(String(describing: error)) } @@ -399,7 +399,7 @@ public class Transaction: ValidateChecksums { .lazy .map { signed -> Proto_TransactionBody in do { - return try Proto_TransactionBody(contiguousBytes: signed.bodyBytes) + return try Proto_TransactionBody(serializedBytes: signed.bodyBytes) } catch { throw HError.fromProtobuf(String(describing: error)) } diff --git a/Sources/Hedera/Transaction/Transaction+FromProtobuf.swift b/Sources/Hedera/Transaction/Transaction+FromProtobuf.swift index 1eaee783..622f979e 100644 --- a/Sources/Hedera/Transaction/Transaction+FromProtobuf.swift +++ b/Sources/Hedera/Transaction/Transaction+FromProtobuf.swift @@ -205,6 +205,20 @@ extension Transaction { case .tokenReject(let value): let value = try intoOnlyValue(value) return try TokenRejectTransaction(protobuf: firstBody, value) + + case .nodeCreate(let value): + let value = try intoOnlyValue(value) + return try NodeCreateTransaction(protobuf: firstBody, value) + + case .nodeUpdate(let value): + let value = try intoOnlyValue(value) + return try NodeUpdateTransaction(protobuf: firstBody, value) + + case .nodeDelete(let value): + let value = try intoOnlyValue(value) + return try NodeDeleteTransaction(protobuf: firstBody, value) + } + } } diff --git a/Sources/Hedera/Transaction/TransactionSources.swift b/Sources/Hedera/Transaction/TransactionSources.swift index ad864028..f20aff92 100644 --- a/Sources/Hedera/Transaction/TransactionSources.swift +++ b/Sources/Hedera/Transaction/TransactionSources.swift @@ -153,7 +153,7 @@ extension TransactionSources { throw HError.fromProtobuf("Transaction had no signed transaction bytes") } - return try Proto_SignedTransaction(contiguousBytes: transaction.signedTransactionBytes) + return try Proto_SignedTransaction(serializedBytes: transaction.signedTransactionBytes) } // ensure all signers (if any) are consistent for all signed transactions. @@ -182,7 +182,7 @@ extension TransactionSources { signedTx -> (transactionId: TransactionId, nodeAccountId: AccountId) in let transactionBody: Proto_TransactionBody do { - transactionBody = try Proto_TransactionBody(contiguousBytes: signedTx.bodyBytes) + transactionBody = try Proto_TransactionBody(serializedBytes: signedTx.bodyBytes) } catch { throw HError.fromProtobuf(String(describing: error)) } diff --git a/Sources/Hedera/TransactionReceipt.swift b/Sources/Hedera/TransactionReceipt.swift index 1bd3b700..62d7a060 100644 --- a/Sources/Hedera/TransactionReceipt.swift +++ b/Sources/Hedera/TransactionReceipt.swift @@ -40,7 +40,8 @@ public struct TransactionReceipt { scheduledTransactionId: TransactionId? = nil, serials: [UInt64]? = nil, duplicates: [TransactionReceipt], - children: [TransactionReceipt] + children: [TransactionReceipt], + nodeId: UInt64 = 0 ) { self.transactionId = transactionId self.status = status @@ -59,6 +60,7 @@ public struct TransactionReceipt { self.serials = serials self.duplicates = duplicates self.children = children + self.nodeId = nodeId } /// The ID of the transaction that this is a receipt for. @@ -133,6 +135,10 @@ public struct TransactionReceipt { /// given top-level id, in consensus order. public let children: [TransactionReceipt] + /// In the receipt of a NodeCreate, NodeUpdate, NodeDelete, the id of the newly created node. + /// An affected node identifier. + public let nodeId: UInt64 + internal init( protobuf proto: Proto_TransactionReceipt, duplicates: [TransactionReceipt], @@ -220,6 +226,7 @@ extension TransactionReceipt: TryProtobufCodable { exchangeRates?.toProtobufInto(&proto.exchangeRate) scheduledTransactionId?.toProtobufInto(&proto.scheduledTransactionID) proto.serialNumbers = serials?.map(Int64.init) ?? [] + proto.nodeID = nodeId } } } diff --git a/Sources/HederaProtobufs/Services/address_book_service.grpc.swift b/Sources/HederaProtobufs/Services/address_book_service.grpc.swift new file mode 100644 index 00000000..26bfff14 --- /dev/null +++ b/Sources/HederaProtobufs/Services/address_book_service.grpc.swift @@ -0,0 +1,528 @@ +// +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the protocol buffer compiler. +// Source: address_book_service.proto +// +import GRPC +import NIO +import NIOConcurrencyHelpers +import SwiftProtobuf + + +///* +/// The Address Book service provides the ability for Hedera network node +/// administrators to add, update, and remove consensus nodes. This addition, +/// update, or removal of a consensus node requires governing council approval, +/// but each node operator may update their own operational attributes without +/// additional approval, reducing overhead for routine operations. +/// +/// Most operations are `privileged operations` and require governing council +/// approval. +/// +/// ### For a node creation transaction. +/// - The node operator SHALL create a `createNode` transaction. +/// - The node operator SHALL sign this transaction with the active `key` for +/// the account to be assigned as the "node account". +/// - The node operator MUST deliver the signed transaction to the Hedera +/// council representative. +/// - The Hedera council representative SHALL arrange for council members to +/// review and sign the transaction. +/// - Once sufficient council members have signed the transaction, the +/// Hedera council representative SHALL submit the transaction to the +/// network. +/// - Upon receipt of a valid and signed node creation transaction the network +/// software SHALL +/// - Validate the threshold signature for the Hedera governing council +/// - Validate the signature of the active `key` for the account to be +/// assigned as the "node account". +/// - Create the new node in state, this new node SHALL NOT be active in the +/// network at this time. +/// - When executing the next `freeze` transaction with `freeze_type` set to +/// `PREPARE_UPGRADE`, update network configuration and bring the +/// new node to an active status within the network. The node to be added +/// SHALL be active in the network following this upgrade. +/// +/// ### For a node deletion transaction. +/// - The node operator or Hedera council representative SHALL create a +/// `deleteNode` transaction. +/// - If the node operator creates the transaction +/// - The node operator MUST sign this transaction with the active `key` +/// for the account assigned as the "node account". +/// - The node operator SHALL deliver the signed transaction to the Hedera +/// council representative. +/// - The Hedera council representative SHALL arrange for council members to +/// review and sign the transaction. +/// - Once sufficient council members have signed the transaction, the +/// Hedera council representative SHALL submit the transaction to the +/// network. +/// - Upon receipt of a valid and signed node deletion transaction the network +/// software SHALL +/// - Validate the threshold signature for the Hedera governing council +/// - Remove the existing node from network state. The node SHALL still +/// be active in the network at this time. +/// - When executing the next `freeze` transaction with `freeze_type` set to +/// `PREPARE_UPGRADE`, update network configuration and remove the +/// node to be deleted from the network. The node to be deleted SHALL NOT +/// be active in the network following this upgrade. +/// +/// ### For a node update transaction. +/// - The node operator or Hedera council representative SHALL create an +/// `updateNode` transaction. +/// - If the node operator creates the transaction +/// - The node operator MUST sign this transaction with the active `key` +/// for the account assigned as the current "node account". +/// - If the transaction changes the value of the "node account" the +/// node operator MUST _also_ sign this transaction with the active `key` +/// for the account to be assigned as the new "node account". +/// - The node operator SHALL submit the transaction to the +/// network. Hedera council approval SHALL NOT be sought for this +/// transaction +/// - If the Hedera council representative creates the transaction +/// - The Hedera council representative SHALL arrange for council members +/// to review and sign the transaction. +/// - Once sufficient council members have signed the transaction, the +/// Hedera council representative SHALL submit the transaction to the +/// network. +/// - Upon receipt of a valid and signed node update transaction the network +/// software SHALL +/// - If the transaction is signed by the Hedera governing council +/// - Validate the threshold signature for the Hedera governing council +/// - If the transaction is signed by the active `key` for the node account +/// - Validate the signature of the active `key` for the account assigned +/// as the "node account". +/// - If the transaction modifies the value of the "node account", +/// - Validate the signature of the _new_ `key` for the account to be +/// assigned as the new "node account". +/// - Modify the node information held in network state with the changes +/// requested in the update transaction. The node changes SHALL NOT be +/// applied to network configuration, and SHALL NOT affect network +/// operation at this time. +/// - When executing the next `freeze` transaction with `freeze_type` set to +/// `PREPARE_UPGRADE`, update network configuration according to the +/// modified information in network state. The requested changes SHALL +/// affect network operation following this upgrade. +/// +/// Usage: instantiate `Proto_AddressBookServiceClient`, then call methods of this protocol to make API calls. +public protocol Proto_AddressBookServiceClientProtocol: GRPCClient { + var serviceName: String { get } + var interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? { get } + + func createNode( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> UnaryCall + + func deleteNode( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> UnaryCall + + func updateNode( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> UnaryCall +} + +extension Proto_AddressBookServiceClientProtocol { + public var serviceName: String { + return "proto.AddressBookService" + } + + ///* + /// A transaction to create a new consensus node in the network. + /// address book. + ///

+ /// This transaction, once complete, SHALL add a new consensus node to the + /// network state.
+ /// The new consensus node SHALL remain in state, but SHALL NOT participate + /// in network consensus until the network updates the network configuration. + ///

+ /// Hedera governing council authorization is REQUIRED for this transaction. + /// + /// - Parameters: + /// - request: Request to send to createNode. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func createNode( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.createNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makecreateNodeInterceptors() ?? [] + ) + } + + ///* + /// A transaction to remove a consensus node from the network address + /// book. + ///

+ /// This transaction, once complete, SHALL remove the identified consensus + /// node from the network state. + ///

+ /// Hedera governing council authorization is REQUIRED for this transaction. + /// + /// - Parameters: + /// - request: Request to send to deleteNode. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func deleteNode( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.deleteNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makedeleteNodeInterceptors() ?? [] + ) + } + + ///* + /// A transaction to update an existing consensus node from the network + /// address book. + ///

+ /// This transaction, once complete, SHALL modify the identified consensus + /// node state as requested. + ///

+ /// This transaction MAY be authorized by either the node operator OR the + /// Hedera governing council. + /// + /// - Parameters: + /// - request: Request to send to updateNode. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func updateNode( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.updateNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeupdateNodeInterceptors() ?? [] + ) + } +} + +@available(*, deprecated) +extension Proto_AddressBookServiceClient: @unchecked Sendable {} + +@available(*, deprecated, renamed: "Proto_AddressBookServiceNIOClient") +public final class Proto_AddressBookServiceClient: Proto_AddressBookServiceClientProtocol { + private let lock = Lock() + private var _defaultCallOptions: CallOptions + private var _interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? + public let channel: GRPCChannel + public var defaultCallOptions: CallOptions { + get { self.lock.withLock { return self._defaultCallOptions } } + set { self.lock.withLockVoid { self._defaultCallOptions = newValue } } + } + public var interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? { + get { self.lock.withLock { return self._interceptors } } + set { self.lock.withLockVoid { self._interceptors = newValue } } + } + + /// Creates a client for the proto.AddressBookService service. + /// + /// - Parameters: + /// - channel: `GRPCChannel` to the service host. + /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + /// - interceptors: A factory providing interceptors for each RPC. + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions(), + interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? = nil + ) { + self.channel = channel + self._defaultCallOptions = defaultCallOptions + self._interceptors = interceptors + } +} + +public struct Proto_AddressBookServiceNIOClient: Proto_AddressBookServiceClientProtocol { + public var channel: GRPCChannel + public var defaultCallOptions: CallOptions + public var interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? + + /// Creates a client for the proto.AddressBookService service. + /// + /// - Parameters: + /// - channel: `GRPCChannel` to the service host. + /// - defaultCallOptions: Options to use for each service call if the user doesn't provide them. + /// - interceptors: A factory providing interceptors for each RPC. + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions(), + interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? = nil + ) { + self.channel = channel + self.defaultCallOptions = defaultCallOptions + self.interceptors = interceptors + } +} + +///* +/// The Address Book service provides the ability for Hedera network node +/// administrators to add, update, and remove consensus nodes. This addition, +/// update, or removal of a consensus node requires governing council approval, +/// but each node operator may update their own operational attributes without +/// additional approval, reducing overhead for routine operations. +/// +/// Most operations are `privileged operations` and require governing council +/// approval. +/// +/// ### For a node creation transaction. +/// - The node operator SHALL create a `createNode` transaction. +/// - The node operator SHALL sign this transaction with the active `key` for +/// the account to be assigned as the "node account". +/// - The node operator MUST deliver the signed transaction to the Hedera +/// council representative. +/// - The Hedera council representative SHALL arrange for council members to +/// review and sign the transaction. +/// - Once sufficient council members have signed the transaction, the +/// Hedera council representative SHALL submit the transaction to the +/// network. +/// - Upon receipt of a valid and signed node creation transaction the network +/// software SHALL +/// - Validate the threshold signature for the Hedera governing council +/// - Validate the signature of the active `key` for the account to be +/// assigned as the "node account". +/// - Create the new node in state, this new node SHALL NOT be active in the +/// network at this time. +/// - When executing the next `freeze` transaction with `freeze_type` set to +/// `PREPARE_UPGRADE`, update network configuration and bring the +/// new node to an active status within the network. The node to be added +/// SHALL be active in the network following this upgrade. +/// +/// ### For a node deletion transaction. +/// - The node operator or Hedera council representative SHALL create a +/// `deleteNode` transaction. +/// - If the node operator creates the transaction +/// - The node operator MUST sign this transaction with the active `key` +/// for the account assigned as the "node account". +/// - The node operator SHALL deliver the signed transaction to the Hedera +/// council representative. +/// - The Hedera council representative SHALL arrange for council members to +/// review and sign the transaction. +/// - Once sufficient council members have signed the transaction, the +/// Hedera council representative SHALL submit the transaction to the +/// network. +/// - Upon receipt of a valid and signed node deletion transaction the network +/// software SHALL +/// - Validate the threshold signature for the Hedera governing council +/// - Remove the existing node from network state. The node SHALL still +/// be active in the network at this time. +/// - When executing the next `freeze` transaction with `freeze_type` set to +/// `PREPARE_UPGRADE`, update network configuration and remove the +/// node to be deleted from the network. The node to be deleted SHALL NOT +/// be active in the network following this upgrade. +/// +/// ### For a node update transaction. +/// - The node operator or Hedera council representative SHALL create an +/// `updateNode` transaction. +/// - If the node operator creates the transaction +/// - The node operator MUST sign this transaction with the active `key` +/// for the account assigned as the current "node account". +/// - If the transaction changes the value of the "node account" the +/// node operator MUST _also_ sign this transaction with the active `key` +/// for the account to be assigned as the new "node account". +/// - The node operator SHALL submit the transaction to the +/// network. Hedera council approval SHALL NOT be sought for this +/// transaction +/// - If the Hedera council representative creates the transaction +/// - The Hedera council representative SHALL arrange for council members +/// to review and sign the transaction. +/// - Once sufficient council members have signed the transaction, the +/// Hedera council representative SHALL submit the transaction to the +/// network. +/// - Upon receipt of a valid and signed node update transaction the network +/// software SHALL +/// - If the transaction is signed by the Hedera governing council +/// - Validate the threshold signature for the Hedera governing council +/// - If the transaction is signed by the active `key` for the node account +/// - Validate the signature of the active `key` for the account assigned +/// as the "node account". +/// - If the transaction modifies the value of the "node account", +/// - Validate the signature of the _new_ `key` for the account to be +/// assigned as the new "node account". +/// - Modify the node information held in network state with the changes +/// requested in the update transaction. The node changes SHALL NOT be +/// applied to network configuration, and SHALL NOT affect network +/// operation at this time. +/// - When executing the next `freeze` transaction with `freeze_type` set to +/// `PREPARE_UPGRADE`, update network configuration according to the +/// modified information in network state. The requested changes SHALL +/// affect network operation following this upgrade. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public protocol Proto_AddressBookServiceAsyncClientProtocol: GRPCClient { + static var serviceDescriptor: GRPCServiceDescriptor { get } + var interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? { get } + + func makeCreateNodeCall( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall + + func makeDeleteNodeCall( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall + + func makeUpdateNodeCall( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall +} + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +extension Proto_AddressBookServiceAsyncClientProtocol { + public static var serviceDescriptor: GRPCServiceDescriptor { + return Proto_AddressBookServiceClientMetadata.serviceDescriptor + } + + public var interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? { + return nil + } + + public func makeCreateNodeCall( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.createNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makecreateNodeInterceptors() ?? [] + ) + } + + public func makeDeleteNodeCall( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.deleteNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makedeleteNodeInterceptors() ?? [] + ) + } + + public func makeUpdateNodeCall( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.updateNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeupdateNodeInterceptors() ?? [] + ) + } +} + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +extension Proto_AddressBookServiceAsyncClientProtocol { + public func createNode( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) async throws -> Proto_TransactionResponse { + return try await self.performAsyncUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.createNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makecreateNodeInterceptors() ?? [] + ) + } + + public func deleteNode( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) async throws -> Proto_TransactionResponse { + return try await self.performAsyncUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.deleteNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makedeleteNodeInterceptors() ?? [] + ) + } + + public func updateNode( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) async throws -> Proto_TransactionResponse { + return try await self.performAsyncUnaryCall( + path: Proto_AddressBookServiceClientMetadata.Methods.updateNode.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeupdateNodeInterceptors() ?? [] + ) + } +} + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public struct Proto_AddressBookServiceAsyncClient: Proto_AddressBookServiceAsyncClientProtocol { + public var channel: GRPCChannel + public var defaultCallOptions: CallOptions + public var interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? + + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions(), + interceptors: Proto_AddressBookServiceClientInterceptorFactoryProtocol? = nil + ) { + self.channel = channel + self.defaultCallOptions = defaultCallOptions + self.interceptors = interceptors + } +} + +public protocol Proto_AddressBookServiceClientInterceptorFactoryProtocol: Sendable { + + /// - Returns: Interceptors to use when invoking 'createNode'. + func makecreateNodeInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'deleteNode'. + func makedeleteNodeInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'updateNode'. + func makeupdateNodeInterceptors() -> [ClientInterceptor] +} + +public enum Proto_AddressBookServiceClientMetadata { + public static let serviceDescriptor = GRPCServiceDescriptor( + name: "AddressBookService", + fullName: "proto.AddressBookService", + methods: [ + Proto_AddressBookServiceClientMetadata.Methods.createNode, + Proto_AddressBookServiceClientMetadata.Methods.deleteNode, + Proto_AddressBookServiceClientMetadata.Methods.updateNode, + ] + ) + + public enum Methods { + public static let createNode = GRPCMethodDescriptor( + name: "createNode", + path: "/proto.AddressBookService/createNode", + type: GRPCCallType.unary + ) + + public static let deleteNode = GRPCMethodDescriptor( + name: "deleteNode", + path: "/proto.AddressBookService/deleteNode", + type: GRPCCallType.unary + ) + + public static let updateNode = GRPCMethodDescriptor( + name: "updateNode", + path: "/proto.AddressBookService/updateNode", + type: GRPCCallType.unary + ) + } +} + diff --git a/Sources/HederaProtobufs/Services/basic_types.pb.swift b/Sources/HederaProtobufs/Services/basic_types.pb.swift index 8bd42b87..5d0c428f 100644 --- a/Sources/HederaProtobufs/Services/basic_types.pb.swift +++ b/Sources/HederaProtobufs/Services/basic_types.pb.swift @@ -744,6 +744,18 @@ public enum Proto_HederaFunctionality: SwiftProtobuf.Enum { ///* /// Transfer one or more token balances held by the requesting account to the treasury for each token type. case tokenReject // = 92 + + ///* + /// Airdrop one or more tokens to one or more accounts. + case tokenAirdrop // = 93 + + ///* + /// Remove one or more pending airdrops from state on behalf of the sender(s) for each airdrop. + case tokenCancelAirdrop // = 94 + + ///* + /// Claim one or more pending airdrops + case tokenClaimAirdrop // = 95 case UNRECOGNIZED(Int) public init() { @@ -831,6 +843,9 @@ public enum Proto_HederaFunctionality: SwiftProtobuf.Enum { case 90: self = .nodeUpdate case 91: self = .nodeDelete case 92: self = .tokenReject + case 93: self = .tokenAirdrop + case 94: self = .tokenCancelAirdrop + case 95: self = .tokenClaimAirdrop default: self = .UNRECOGNIZED(rawValue) } } @@ -916,6 +931,9 @@ public enum Proto_HederaFunctionality: SwiftProtobuf.Enum { case .nodeUpdate: return 90 case .nodeDelete: return 91 case .tokenReject: return 92 + case .tokenAirdrop: return 93 + case .tokenCancelAirdrop: return 94 + case .tokenClaimAirdrop: return 95 case .UNRECOGNIZED(let i): return i } } @@ -1006,6 +1024,9 @@ extension Proto_HederaFunctionality: CaseIterable { .nodeUpdate, .nodeDelete, .tokenReject, + .tokenAirdrop, + .tokenCancelAirdrop, + .tokenClaimAirdrop, ] } @@ -2884,6 +2905,144 @@ public struct Proto_StakingInfo { fileprivate var _stakePeriodStart: Proto_Timestamp? = nil } +///* +/// A unique, composite, identifier for a pending airdrop. +/// +/// Each pending airdrop SHALL be uniquely identified by a PendingAirdropId. +/// A PendingAirdropId SHALL be recorded when created and MUST be provided in any transaction +/// that would modify that pending airdrop (such as a `claimAirdrop` or `cancelAirdrop`). +public struct Proto_PendingAirdropId { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + ///* + /// A sending account.
+ /// This is the account that initiated, and SHALL fund, this pending airdrop.
+ /// This field is REQUIRED. + public var senderID: Proto_AccountID { + get {return _senderID ?? Proto_AccountID()} + set {_senderID = newValue} + } + /// Returns true if `senderID` has been explicitly set. + public var hasSenderID: Bool {return self._senderID != nil} + /// Clears the value of `senderID`. Subsequent reads from it will return its default value. + public mutating func clearSenderID() {self._senderID = nil} + + ///* + /// A receiving account.
+ /// This is the ID of the account that SHALL receive the airdrop.
+ /// This field is REQUIRED. + public var receiverID: Proto_AccountID { + get {return _receiverID ?? Proto_AccountID()} + set {_receiverID = newValue} + } + /// Returns true if `receiverID` has been explicitly set. + public var hasReceiverID: Bool {return self._receiverID != nil} + /// Clears the value of `receiverID`. Subsequent reads from it will return its default value. + public mutating func clearReceiverID() {self._receiverID = nil} + + public var tokenReference: Proto_PendingAirdropId.OneOf_TokenReference? = nil + + ///* + /// A token ID.
+ /// This is the type of token for a fungible/common token airdrop.
+ /// This field is REQUIRED for a fungible/common token and MUST NOT be used for a + /// non-fungible/unique token. + public var fungibleTokenType: Proto_TokenID { + get { + if case .fungibleTokenType(let v)? = tokenReference {return v} + return Proto_TokenID() + } + set {tokenReference = .fungibleTokenType(newValue)} + } + + ///* + /// The id of a single NFT, consisting of a Token ID and serial number.
+ /// This is the type of token for a non-fungible/unique token airdrop.
+ /// This field is REQUIRED for a non-fungible/unique token and MUST NOT be used for a + /// fungible/common token. + public var nonFungibleToken: Proto_NftID { + get { + if case .nonFungibleToken(let v)? = tokenReference {return v} + return Proto_NftID() + } + set {tokenReference = .nonFungibleToken(newValue)} + } + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public enum OneOf_TokenReference: Equatable { + ///* + /// A token ID.
+ /// This is the type of token for a fungible/common token airdrop.
+ /// This field is REQUIRED for a fungible/common token and MUST NOT be used for a + /// non-fungible/unique token. + case fungibleTokenType(Proto_TokenID) + ///* + /// The id of a single NFT, consisting of a Token ID and serial number.
+ /// This is the type of token for a non-fungible/unique token airdrop.
+ /// This field is REQUIRED for a non-fungible/unique token and MUST NOT be used for a + /// fungible/common token. + case nonFungibleToken(Proto_NftID) + + #if !swift(>=4.1) + public static func ==(lhs: Proto_PendingAirdropId.OneOf_TokenReference, rhs: Proto_PendingAirdropId.OneOf_TokenReference) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.fungibleTokenType, .fungibleTokenType): return { + guard case .fungibleTokenType(let l) = lhs, case .fungibleTokenType(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.nonFungibleToken, .nonFungibleToken): return { + guard case .nonFungibleToken(let l) = lhs, case .nonFungibleToken(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif + } + + public init() {} + + fileprivate var _senderID: Proto_AccountID? = nil + fileprivate var _receiverID: Proto_AccountID? = nil +} + +///* +/// A single pending airdrop value. +/// +/// This message SHALL record the airdrop amount for a fungible/common token.
+/// This message SHOULD be null for a non-fungible/unique token.
+/// If a non-null `PendingAirdropValue` is set for a non-fungible/unique token, the amount +/// field MUST be `0`. +/// +/// It is RECOMMENDED that implementations store pending airdrop information as a key-value map +/// from `PendingAirdropId` to `PendingAirdropValue`, with a `null` value used for non-fungible +/// pending airdrops. +public struct Proto_PendingAirdropValue { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + ///* + /// An amount to transfer for fungible/common tokens.
+ /// This is expressed in the smallest available units for that token + /// (i.e. 10-`decimals` whole tokens).
+ /// This amount SHALL be transferred from the sender to the receiver, if claimed.
+ /// If the token is a fungible/common token, this value MUST be strictly greater than `0`. + /// If the token is a non-fungible/unique token, this message SHOULD NOT be set, and if + /// set, this field MUST be `0`. + public var amount: UInt64 = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + #if swift(>=5.5) && canImport(_Concurrency) extension Proto_TokenType: @unchecked Sendable {} extension Proto_SubType: @unchecked Sendable {} @@ -2938,6 +3097,9 @@ extension Proto_TokenBalances: @unchecked Sendable {} extension Proto_TokenAssociation: @unchecked Sendable {} extension Proto_StakingInfo: @unchecked Sendable {} extension Proto_StakingInfo.OneOf_StakedID: @unchecked Sendable {} +extension Proto_PendingAirdropId: @unchecked Sendable {} +extension Proto_PendingAirdropId.OneOf_TokenReference: @unchecked Sendable {} +extension Proto_PendingAirdropValue: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. @@ -3081,6 +3243,9 @@ extension Proto_HederaFunctionality: SwiftProtobuf._ProtoNameProviding { 90: .same(proto: "NodeUpdate"), 91: .same(proto: "NodeDelete"), 92: .same(proto: "TokenReject"), + 93: .same(proto: "TokenAirdrop"), + 94: .same(proto: "TokenCancelAirdrop"), + 95: .same(proto: "TokenClaimAirdrop"), ] } @@ -5259,3 +5424,117 @@ extension Proto_StakingInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem return true } } + +extension Proto_PendingAirdropId: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".PendingAirdropId" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "sender_id"), + 2: .standard(proto: "receiver_id"), + 3: .standard(proto: "fungible_token_type"), + 4: .standard(proto: "non_fungible_token"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &self._senderID) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._receiverID) }() + case 3: try { + var v: Proto_TokenID? + var hadOneofValue = false + if let current = self.tokenReference { + hadOneofValue = true + if case .fungibleTokenType(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.tokenReference = .fungibleTokenType(v) + } + }() + case 4: try { + var v: Proto_NftID? + var hadOneofValue = false + if let current = self.tokenReference { + hadOneofValue = true + if case .nonFungibleToken(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.tokenReference = .nonFungibleToken(v) + } + }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._senderID { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = self._receiverID { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + switch self.tokenReference { + case .fungibleTokenType?: try { + guard case .fungibleTokenType(let v)? = self.tokenReference else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + }() + case .nonFungibleToken?: try { + guard case .nonFungibleToken(let v)? = self.tokenReference else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + }() + case nil: break + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_PendingAirdropId, rhs: Proto_PendingAirdropId) -> Bool { + if lhs._senderID != rhs._senderID {return false} + if lhs._receiverID != rhs._receiverID {return false} + if lhs.tokenReference != rhs.tokenReference {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Proto_PendingAirdropValue: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".PendingAirdropValue" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "amount"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularUInt64Field(value: &self.amount) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.amount != 0 { + try visitor.visitSingularUInt64Field(value: self.amount, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_PendingAirdropValue, rhs: Proto_PendingAirdropValue) -> Bool { + if lhs.amount != rhs.amount {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/HederaProtobufs/Services/response_code.pb.swift b/Sources/HederaProtobufs/Services/response_code.pb.swift index 1585fd77..ba2d1ad6 100644 --- a/Sources/HederaProtobufs/Services/response_code.pb.swift +++ b/Sources/HederaProtobufs/Services/response_code.pb.swift @@ -1324,6 +1324,33 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum { /// /// The node account is not allowed to be updated case updateNodeAccountNotAllowed // = 359 + + /// + /// The token has no metadata or supply key + case tokenHasNoMetadataOrSupplyKey // = 360 + + ///* + /// The transaction attempted to the use an empty List of `PendingAirdropId`. + case emptyPendingAirdropIDList // = 361 + + ///* + /// The transaction attempted to the same `PendingAirdropId` twice. + case pendingAirdropIDRepeated // = 362 + + ///* + /// The transaction attempted to use more than the allowed number of `PendingAirdropId`. + case maxPendingAirdropIDExceeded // = 363 + + /// + /// A pending airdrop already exists for the specified NFT. + case pendingNftAirdropAlreadyExists // = 364 + + /// + /// The identified account is sender for one or more pending airdrop(s) + /// and cannot be deleted.
+ /// Requester should cancel all pending airdrops before resending + /// this transaction. + case accountHasPendingAirdrops // = 365 case UNRECOGNIZED(Int) public init() { @@ -1650,6 +1677,12 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum { case 357: self = .invalidIpv4Address case 358: self = .emptyTokenReferenceList case 359: self = .updateNodeAccountNotAllowed + case 360: self = .tokenHasNoMetadataOrSupplyKey + case 361: self = .emptyPendingAirdropIDList + case 362: self = .pendingAirdropIDRepeated + case 363: self = .maxPendingAirdropIDExceeded + case 364: self = .pendingNftAirdropAlreadyExists + case 365: self = .accountHasPendingAirdrops default: self = .UNRECOGNIZED(rawValue) } } @@ -1974,6 +2007,12 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum { case .invalidIpv4Address: return 357 case .emptyTokenReferenceList: return 358 case .updateNodeAccountNotAllowed: return 359 + case .tokenHasNoMetadataOrSupplyKey: return 360 + case .emptyPendingAirdropIDList: return 361 + case .pendingAirdropIDRepeated: return 362 + case .maxPendingAirdropIDExceeded: return 363 + case .pendingNftAirdropAlreadyExists: return 364 + case .accountHasPendingAirdrops: return 365 case .UNRECOGNIZED(let i): return i } } @@ -2303,6 +2342,12 @@ extension Proto_ResponseCodeEnum: CaseIterable { .invalidIpv4Address, .emptyTokenReferenceList, .updateNodeAccountNotAllowed, + .tokenHasNoMetadataOrSupplyKey, + .emptyPendingAirdropIDList, + .pendingAirdropIDRepeated, + .maxPendingAirdropIDExceeded, + .pendingNftAirdropAlreadyExists, + .accountHasPendingAirdrops, ] } @@ -2634,5 +2679,11 @@ extension Proto_ResponseCodeEnum: SwiftProtobuf._ProtoNameProviding { 357: .same(proto: "INVALID_IPV4_ADDRESS"), 358: .same(proto: "EMPTY_TOKEN_REFERENCE_LIST"), 359: .same(proto: "UPDATE_NODE_ACCOUNT_NOT_ALLOWED"), + 360: .same(proto: "TOKEN_HAS_NO_METADATA_OR_SUPPLY_KEY"), + 361: .same(proto: "EMPTY_PENDING_AIRDROP_ID_LIST"), + 362: .same(proto: "PENDING_AIRDROP_ID_REPEATED"), + 363: .same(proto: "MAX_PENDING_AIRDROP_ID_EXCEEDED"), + 364: .same(proto: "PENDING_NFT_AIRDROP_ALREADY_EXISTS"), + 365: .same(proto: "ACCOUNT_HAS_PENDING_AIRDROPS"), ] } diff --git a/Sources/HederaProtobufs/Services/schedulable_transaction_body.pb.swift b/Sources/HederaProtobufs/Services/schedulable_transaction_body.pb.swift index 6c153361..6c87c9bc 100644 --- a/Sources/HederaProtobufs/Services/schedulable_transaction_body.pb.swift +++ b/Sources/HederaProtobufs/Services/schedulable_transaction_body.pb.swift @@ -496,6 +496,36 @@ public struct Proto_SchedulableTransactionBody { set {_uniqueStorage()._data = .tokenReject(newValue)} } + ///* + /// Transaction body for a scheduled transaction to cancel an airdrop. + public var tokenCancelAirdrop: Proto_TokenCancelAirdropTransactionBody { + get { + if case .tokenCancelAirdrop(let v)? = _storage._data {return v} + return Proto_TokenCancelAirdropTransactionBody() + } + set {_uniqueStorage()._data = .tokenCancelAirdrop(newValue)} + } + + ///* + /// Transaction body for a scheduled transaction to claim an airdrop. + public var tokenClaimAirdrop: Proto_TokenClaimAirdropTransactionBody { + get { + if case .tokenClaimAirdrop(let v)? = _storage._data {return v} + return Proto_TokenClaimAirdropTransactionBody() + } + set {_uniqueStorage()._data = .tokenClaimAirdrop(newValue)} + } + + ///* + /// Transaction body for a scheduled transaction to airdrop tokens. + public var tokenAirdrop: Proto_TokenAirdropTransactionBody { + get { + if case .tokenAirdrop(let v)? = _storage._data {return v} + return Proto_TokenAirdropTransactionBody() + } + set {_uniqueStorage()._data = .tokenAirdrop(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() ///* @@ -644,6 +674,15 @@ public struct Proto_SchedulableTransactionBody { /// Custom fees and royalties defined for the tokens rejected /// SHALL NOT be charged for this transaction. case tokenReject(Proto_TokenRejectTransactionBody) + ///* + /// Transaction body for a scheduled transaction to cancel an airdrop. + case tokenCancelAirdrop(Proto_TokenCancelAirdropTransactionBody) + ///* + /// Transaction body for a scheduled transaction to claim an airdrop. + case tokenClaimAirdrop(Proto_TokenClaimAirdropTransactionBody) + ///* + /// Transaction body for a scheduled transaction to airdrop tokens. + case tokenAirdrop(Proto_TokenAirdropTransactionBody) #if !swift(>=4.1) public static func ==(lhs: Proto_SchedulableTransactionBody.OneOf_Data, rhs: Proto_SchedulableTransactionBody.OneOf_Data) -> Bool { @@ -823,6 +862,18 @@ public struct Proto_SchedulableTransactionBody { guard case .tokenReject(let l) = lhs, case .tokenReject(let r) = rhs else { preconditionFailure() } return l == r }() + case (.tokenCancelAirdrop, .tokenCancelAirdrop): return { + guard case .tokenCancelAirdrop(let l) = lhs, case .tokenCancelAirdrop(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.tokenClaimAirdrop, .tokenClaimAirdrop): return { + guard case .tokenClaimAirdrop(let l) = lhs, case .tokenClaimAirdrop(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.tokenAirdrop, .tokenAirdrop): return { + guard case .tokenAirdrop(let l) = lhs, case .tokenAirdrop(let r) = rhs else { preconditionFailure() } + return l == r + }() default: return false } } @@ -891,6 +942,9 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf 43: .same(proto: "nodeUpdate"), 44: .same(proto: "nodeDelete"), 45: .same(proto: "tokenReject"), + 46: .same(proto: "tokenCancelAirdrop"), + 47: .same(proto: "tokenClaimAirdrop"), + 48: .same(proto: "tokenAirdrop"), ] fileprivate class _StorageClass { @@ -1493,6 +1547,45 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf _storage._data = .tokenReject(v) } }() + case 46: try { + var v: Proto_TokenCancelAirdropTransactionBody? + var hadOneofValue = false + if let current = _storage._data { + hadOneofValue = true + if case .tokenCancelAirdrop(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._data = .tokenCancelAirdrop(v) + } + }() + case 47: try { + var v: Proto_TokenClaimAirdropTransactionBody? + var hadOneofValue = false + if let current = _storage._data { + hadOneofValue = true + if case .tokenClaimAirdrop(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._data = .tokenClaimAirdrop(v) + } + }() + case 48: try { + var v: Proto_TokenAirdropTransactionBody? + var hadOneofValue = false + if let current = _storage._data { + hadOneofValue = true + if case .tokenAirdrop(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._data = .tokenAirdrop(v) + } + }() default: break } } @@ -1684,6 +1777,18 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf guard case .tokenReject(let v)? = _storage._data else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 45) }() + case .tokenCancelAirdrop?: try { + guard case .tokenCancelAirdrop(let v)? = _storage._data else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 46) + }() + case .tokenClaimAirdrop?: try { + guard case .tokenClaimAirdrop(let v)? = _storage._data else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 47) + }() + case .tokenAirdrop?: try { + guard case .tokenAirdrop(let v)? = _storage._data else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 48) + }() case nil: break } } diff --git a/Sources/HederaProtobufs/Services/state_token_account.pb.swift b/Sources/HederaProtobufs/Services/state_token_account.pb.swift index b875a020..7e8895a1 100644 --- a/Sources/HederaProtobufs/Services/state_token_account.pb.swift +++ b/Sources/HederaProtobufs/Services/state_token_account.pb.swift @@ -315,6 +315,23 @@ public struct Proto_Account { set {_uniqueStorage()._firstContractStorageKey = newValue} } + ///* + /// A pending airdrop ID at the head of the linked list for this account + /// from the account airdrops map.
+ /// The account airdrops are connected by including the "next" and "previous" + /// `PendingAirdropID` in each `AccountAirdrop` message. + ///

+ /// This value SHALL NOT be empty if this account is "sender" for any + /// pending airdrop, and SHALL be empty otherwise. + public var headPendingAirdropID: Proto_PendingAirdropId { + get {return _storage._headPendingAirdropID ?? Proto_PendingAirdropId()} + set {_uniqueStorage()._headPendingAirdropID = newValue} + } + /// Returns true if `headPendingAirdropID` has been explicitly set. + public var hasHeadPendingAirdropID: Bool {return _storage._headPendingAirdropID != nil} + /// Clears the value of `headPendingAirdropID`. Subsequent reads from it will return its default value. + public mutating func clearHeadPendingAirdropID() {_uniqueStorage()._headPendingAirdropID = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() ///* @@ -500,6 +517,7 @@ extension Proto_Account: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa 31: .standard(proto: "number_treasury_titles"), 32: .standard(proto: "expired_and_pending_removal"), 33: .standard(proto: "first_contract_storage_key"), + 34: .standard(proto: "head_pending_airdrop_id"), ] fileprivate class _StorageClass { @@ -535,6 +553,7 @@ extension Proto_Account: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa var _numberTreasuryTitles: UInt32 = 0 var _expiredAndPendingRemoval: Bool = false var _firstContractStorageKey: Data = Data() + var _headPendingAirdropID: Proto_PendingAirdropId? = nil #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -581,6 +600,7 @@ extension Proto_Account: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa _numberTreasuryTitles = source._numberTreasuryTitles _expiredAndPendingRemoval = source._expiredAndPendingRemoval _firstContractStorageKey = source._firstContractStorageKey + _headPendingAirdropID = source._headPendingAirdropID } } @@ -651,6 +671,7 @@ extension Proto_Account: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa case 31: try { try decoder.decodeSingularUInt32Field(value: &_storage._numberTreasuryTitles) }() case 32: try { try decoder.decodeSingularBoolField(value: &_storage._expiredAndPendingRemoval) }() case 33: try { try decoder.decodeSingularBytesField(value: &_storage._firstContractStorageKey) }() + case 34: try { try decoder.decodeSingularMessageField(value: &_storage._headPendingAirdropID) }() default: break } } @@ -767,6 +788,9 @@ extension Proto_Account: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if !_storage._firstContractStorageKey.isEmpty { try visitor.visitSingularBytesField(value: _storage._firstContractStorageKey, fieldNumber: 33) } + try { if let v = _storage._headPendingAirdropID { + try visitor.visitSingularMessageField(value: v, fieldNumber: 34) + } }() } try unknownFields.traverse(visitor: &visitor) } @@ -808,6 +832,7 @@ extension Proto_Account: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if _storage._numberTreasuryTitles != rhs_storage._numberTreasuryTitles {return false} if _storage._expiredAndPendingRemoval != rhs_storage._expiredAndPendingRemoval {return false} if _storage._firstContractStorageKey != rhs_storage._firstContractStorageKey {return false} + if _storage._headPendingAirdropID != rhs_storage._headPendingAirdropID {return false} return true } if !storagesAreEqual {return false} diff --git a/Sources/HederaProtobufs/Services/state_token_account_pending_airdrop.pb.swift b/Sources/HederaProtobufs/Services/state_token_account_pending_airdrop.pb.swift new file mode 100644 index 00000000..00a9d1e9 --- /dev/null +++ b/Sources/HederaProtobufs/Services/state_token_account_pending_airdrop.pb.swift @@ -0,0 +1,192 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: state/token/account_pending_airdrop.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +import Foundation +import SwiftProtobuf + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} + typealias Version = _2 +} + +///* +/// A node within a doubly linked list of pending airdrop references.
+/// This internal state message forms the entries in a doubly-linked list +/// of references to pending airdrop entries that are "owed" by a particular +/// account as "sender". +/// +/// Each entry in this list MUST refer to an existing pending airdrop.
+/// The pending airdrop MUST NOT be claimed.
+/// The pending airdrop MUST NOT be canceled.
+/// The pending airdrop `sender` account's `head_pending_airdrop_id` field +/// MUST match the `pending_airdrop_id` field in this message. +/// +/// ### Record Stream Effects +/// This value is not currently published in the record stream. +public struct Proto_AccountPendingAirdrop { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + ///* + /// The value of the current airdrop id. SHALL NOT be set for non fungible tokens + public var pendingAirdropValue: Proto_PendingAirdropValue { + get {return _storage._pendingAirdropValue ?? Proto_PendingAirdropValue()} + set {_uniqueStorage()._pendingAirdropValue = newValue} + } + /// Returns true if `pendingAirdropValue` has been explicitly set. + public var hasPendingAirdropValue: Bool {return _storage._pendingAirdropValue != nil} + /// Clears the value of `pendingAirdropValue`. Subsequent reads from it will return its default value. + public mutating func clearPendingAirdropValue() {_uniqueStorage()._pendingAirdropValue = nil} + + ///* + /// A pending airdrop identifier.
+ /// This identifies the specific pending airdrop that precedes this position + /// within the doubly linked list of pending airdrops "owed" by the sending + /// account associated with this account airdrop "list". + ///

+ /// This SHALL match `pending_airdrop_id` if this is the only entry + /// in the "list". + public var previousAirdrop: Proto_PendingAirdropId { + get {return _storage._previousAirdrop ?? Proto_PendingAirdropId()} + set {_uniqueStorage()._previousAirdrop = newValue} + } + /// Returns true if `previousAirdrop` has been explicitly set. + public var hasPreviousAirdrop: Bool {return _storage._previousAirdrop != nil} + /// Clears the value of `previousAirdrop`. Subsequent reads from it will return its default value. + public mutating func clearPreviousAirdrop() {_uniqueStorage()._previousAirdrop = nil} + + ///* + /// A pending airdrop identifier.
+ /// This identifies the specific pending airdrop that follows this position + /// within the doubly linked list of pending airdrops "owed" by the sending + /// account associated with this account airdrop "list". + ///

+ /// This SHALL match `pending_airdrop_id` if this is the only entry + /// in the "list". + public var nextAirdrop: Proto_PendingAirdropId { + get {return _storage._nextAirdrop ?? Proto_PendingAirdropId()} + set {_uniqueStorage()._nextAirdrop = newValue} + } + /// Returns true if `nextAirdrop` has been explicitly set. + public var hasNextAirdrop: Bool {return _storage._nextAirdrop != nil} + /// Clears the value of `nextAirdrop`. Subsequent reads from it will return its default value. + public mutating func clearNextAirdrop() {_uniqueStorage()._nextAirdrop = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _storage = _StorageClass.defaultInstance +} + +#if swift(>=5.5) && canImport(_Concurrency) +extension Proto_AccountPendingAirdrop: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +fileprivate let _protobuf_package = "proto" + +extension Proto_AccountPendingAirdrop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".AccountPendingAirdrop" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "pending_airdrop_value"), + 2: .standard(proto: "previous_airdrop"), + 3: .standard(proto: "next_airdrop"), + ] + + fileprivate class _StorageClass { + var _pendingAirdropValue: Proto_PendingAirdropValue? = nil + var _previousAirdrop: Proto_PendingAirdropId? = nil + var _nextAirdrop: Proto_PendingAirdropId? = nil + + #if swift(>=5.10) + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() + #else + static let defaultInstance = _StorageClass() + #endif + + private init() {} + + init(copying source: _StorageClass) { + _pendingAirdropValue = source._pendingAirdropValue + _previousAirdrop = source._previousAirdrop + _nextAirdrop = source._nextAirdrop + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + + public mutating func decodeMessage(decoder: inout D) throws { + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &_storage._pendingAirdropValue) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._previousAirdrop) }() + case 3: try { try decoder.decodeSingularMessageField(value: &_storage._nextAirdrop) }() + default: break + } + } + } + } + + public func traverse(visitor: inout V) throws { + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = _storage._pendingAirdropValue { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = _storage._previousAirdrop { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try { if let v = _storage._nextAirdrop { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_AccountPendingAirdrop, rhs: Proto_AccountPendingAirdrop) -> Bool { + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._pendingAirdropValue != rhs_storage._pendingAirdropValue {return false} + if _storage._previousAirdrop != rhs_storage._previousAirdrop {return false} + if _storage._nextAirdrop != rhs_storage._nextAirdrop {return false} + return true + } + if !storagesAreEqual {return false} + } + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/HederaProtobufs/Services/token_airdrop.pb.swift b/Sources/HederaProtobufs/Services/token_airdrop.pb.swift new file mode 100644 index 00000000..92d0e1de --- /dev/null +++ b/Sources/HederaProtobufs/Services/token_airdrop.pb.swift @@ -0,0 +1,142 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: token_airdrop.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +///* +/// # Token Airdrop +/// Messages used to implement a transaction to "airdrop" tokens.
+/// An "airdrop" is a distribution of tokens from a funding account +/// to one or more recipient accounts, ideally with no action required +/// by the recipient account(s). +/// +/// ### Keywords +/// The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +/// "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this +/// document are to be interpreted as described in [RFC2119](https://www.ietf.org/rfc/rfc2119). + +import Foundation +import SwiftProtobuf + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} + typealias Version = _2 +} + +///* +/// Airdrop one or more tokens to one or more accounts. +/// +/// ### Effects +/// This distributes tokens from the balance of one or more sending account(s) to the balance +/// of one or more recipient accounts. Accounts MAY receive the tokens in one of four ways. +/// +/// - An account already associated to the token to be distributed SHALL receive the +/// airdropped tokens immediately to the recipient account balance.
+/// The fee for this transfer SHALL include the transfer, the airdrop fee, and any custom fees. +/// - An account with available automatic association slots SHALL be automatically +/// associated to the token, and SHALL immediately receive the airdropped tokens to the +/// recipient account balance.
+/// The fee for this transfer SHALL include the transfer, the association, the cost to renew +/// that association once, the airdrop fee, and any custom fees. +/// - An account with "receiver signature required" set SHALL have a "Pending Airdrop" created +/// and must claim that airdrop with a `claimAirdrop` transaction.
+/// The fee for this transfer SHALL include the transfer, the association, the cost to renew +/// that association once, the airdrop fee, and any custom fees. If the pending airdrop is not +/// claimed immediately, the `sender` SHALL pay the cost to renew the token association, and +/// the cost to maintain the pending airdrop, until the pending airdrop is claimed or cancelled. +/// - An account with no available automatic association slots SHALL have a "Pending Airdrop" +/// created and must claim that airdrop with a `claimAirdrop` transaction.
+/// The fee for this transfer SHALL include the transfer, the association, the cost to renew +/// that association once, the airdrop fee, and any custom fees. If the pending airdrop is not +/// claimed immediately, the `sender` SHALL pay the cost to renew the token association, and +/// the cost to maintain the pending airdrop, until the pending airdrop is claimed or cancelled. +/// +/// If an airdrop would create a pending airdrop for a fungible/common token, and a pending airdrop +/// for the same sender, receiver, and token already exists, the existing pending airdrop +/// SHALL be updated to add the new amount to the existing airdrop, rather than creating a new +/// pending airdrop. +/// +/// Any airdrop that completes immediately SHALL be irreversible. Any airdrop that results in a +/// "Pending Airdrop" MAY be canceled via a `cancelAirdrop` transaction. +/// +/// All transfer fees (including custom fees and royalties), as well as the rent cost for the +/// first auto-renewal period for any automatic-association slot occupied by the airdropped +/// tokens, SHALL be charged to the account paying for this transaction. +/// +/// ### Record Stream Effects +/// - Each successful transfer SHALL be recorded in `token_transfer_list` for the transaction record. +/// - Each successful transfer that consumes an automatic association slot SHALL populate the +/// `automatic_association` field for the record. +/// - Each pending transfer _created_ SHALL be added to the `pending_airdrops` field for the record. +/// - Each pending transfer _updated_ SHALL be added to the `pending_airdrops` field for the record. +public struct Proto_TokenAirdropTransactionBody { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + ///* + /// A list of token transfers representing one or more airdrops. + /// The sender for each transfer MUST have sufficient balance to complete the transfers. + /// + /// All token transfers MUST successfully transfer tokens or create a pending airdrop + /// for this transaction to succeed. + /// This list MUST contain between 1 and 10 transfers, inclusive. + /// + /// Note that each transfer of fungible/common tokens requires both a debit and + /// a credit, so each _fungible_ token transfer MUST have _balanced_ entries in the + /// TokenTransferList for that transfer. + public var tokenTransfers: [Proto_TokenTransferList] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +#if swift(>=5.5) && canImport(_Concurrency) +extension Proto_TokenAirdropTransactionBody: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +fileprivate let _protobuf_package = "proto" + +extension Proto_TokenAirdropTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".TokenAirdropTransactionBody" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "token_transfers"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeRepeatedMessageField(value: &self.tokenTransfers) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.tokenTransfers.isEmpty { + try visitor.visitRepeatedMessageField(value: self.tokenTransfers, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_TokenAirdropTransactionBody, rhs: Proto_TokenAirdropTransactionBody) -> Bool { + if lhs.tokenTransfers != rhs.tokenTransfers {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/HederaProtobufs/Services/token_cancel_airdrop.pb.swift b/Sources/HederaProtobufs/Services/token_cancel_airdrop.pb.swift new file mode 100644 index 00000000..928780ab --- /dev/null +++ b/Sources/HederaProtobufs/Services/token_cancel_airdrop.pb.swift @@ -0,0 +1,101 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: token_cancel_airdrop.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +///* +/// # Token Cancel Airdrop +/// Messages used to implement a transaction to cancel a pending airdrop. +/// +/// ### Keywords +/// The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +/// "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this +/// document are to be interpreted as described in [RFC2119](https://www.ietf.org/rfc/rfc2119). + +import Foundation +import SwiftProtobuf + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} + typealias Version = _2 +} + +///* +/// Token cancel airdrop
+/// Remove one or more pending airdrops from state on behalf of the sender(s) +/// for each airdrop. +/// +/// Each pending airdrop canceled SHALL be removed from state and SHALL NOT be available to claim.
+/// Each cancellation SHALL be represented in the transaction body and SHALL NOT be restated +/// in the record file.
+/// All cancellations MUST succeed for this transaction to succeed. +public struct Proto_TokenCancelAirdropTransactionBody { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + ///* + /// A list of one or more pending airdrop identifiers.
+ /// This list declares the set of pending airdrop entries that the client + /// wishes to cancel; on success all listed pending airdrop entries + /// will be removed. + ///

+ /// This transaction MUST be signed by the account referenced by a `sender_id` for + /// each entry in this list.
+ /// This list MUST NOT have any duplicate entries.
+ /// This list MUST contain between 1 and 10 entries, inclusive. + public var pendingAirdrops: [Proto_PendingAirdropId] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +#if swift(>=5.5) && canImport(_Concurrency) +extension Proto_TokenCancelAirdropTransactionBody: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +fileprivate let _protobuf_package = "proto" + +extension Proto_TokenCancelAirdropTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".TokenCancelAirdropTransactionBody" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "pending_airdrops"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeRepeatedMessageField(value: &self.pendingAirdrops) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.pendingAirdrops.isEmpty { + try visitor.visitRepeatedMessageField(value: self.pendingAirdrops, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_TokenCancelAirdropTransactionBody, rhs: Proto_TokenCancelAirdropTransactionBody) -> Bool { + if lhs.pendingAirdrops != rhs.pendingAirdrops {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/HederaProtobufs/Services/token_claim_airdrop.pb.swift b/Sources/HederaProtobufs/Services/token_claim_airdrop.pb.swift new file mode 100644 index 00000000..d1cd47bb --- /dev/null +++ b/Sources/HederaProtobufs/Services/token_claim_airdrop.pb.swift @@ -0,0 +1,105 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: token_claim_airdrop.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +///* +/// # Token Claim Airdrop +/// Messages used to implement a transaction to claim a pending airdrop. +/// +/// ### Keywords +/// The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +/// "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this +/// document are to be interpreted as described in [RFC2119](https://www.ietf.org/rfc/rfc2119). + +import Foundation +import SwiftProtobuf + +// If the compiler emits an error on this type, it is because this file +// was generated by a version of the `protoc` Swift plug-in that is +// incompatible with the version of SwiftProtobuf to which you are linking. +// Please ensure that you are building against the same version of the API +// that was used to generate this file. +fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { + struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} + typealias Version = _2 +} + +///* +/// Token claim airdrop
+/// Complete one or more pending transfers on behalf of the +/// recipient(s) for an airdrop. +/// +/// The sender MUST have sufficient balance to fulfill the airdrop at the +/// time of claim. If the sender does not have sufficient balance, the +/// claim SHALL fail.
+/// Each pending airdrop successfully claimed SHALL be removed from state and +/// SHALL NOT be available to claim again.
+/// Each claim SHALL be represented in the transaction body and +/// SHALL NOT be restated in the record file.
+/// All claims MUST succeed for this transaction to succeed. +/// +/// ### Record Stream Effects +/// The completed transfers SHALL be present in the transfer list. +public struct Proto_TokenClaimAirdropTransactionBody { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + ///* + /// A list of one or more pending airdrop identifiers. + ///

+ /// This transaction MUST be signed by the account identified by + /// the `receiver_id` for each entry in this list.
+ /// This list MUST contain between 1 and 10 entries, inclusive.
+ /// This list MUST NOT have any duplicate entries. + public var pendingAirdrops: [Proto_PendingAirdropId] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +#if swift(>=5.5) && canImport(_Concurrency) +extension Proto_TokenClaimAirdropTransactionBody: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + +// MARK: - Code below here is support for the SwiftProtobuf runtime. + +fileprivate let _protobuf_package = "proto" + +extension Proto_TokenClaimAirdropTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".TokenClaimAirdropTransactionBody" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "pending_airdrops"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeRepeatedMessageField(value: &self.pendingAirdrops) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.pendingAirdrops.isEmpty { + try visitor.visitRepeatedMessageField(value: self.pendingAirdrops, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_TokenClaimAirdropTransactionBody, rhs: Proto_TokenClaimAirdropTransactionBody) -> Bool { + if lhs.pendingAirdrops != rhs.pendingAirdrops {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/HederaProtobufs/Services/token_service.grpc.swift b/Sources/HederaProtobufs/Services/token_service.grpc.swift index 602086af..5c3c0315 100644 --- a/Sources/HederaProtobufs/Services/token_service.grpc.swift +++ b/Sources/HederaProtobufs/Services/token_service.grpc.swift @@ -113,6 +113,31 @@ public protocol Proto_TokenServiceClientProtocol: GRPCClient { _ request: Proto_Transaction, callOptions: CallOptions? ) -> UnaryCall + + func updateNfts( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> UnaryCall + + func rejectToken( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> UnaryCall + + func airdropTokens( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> UnaryCall + + func cancelAirdrop( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> UnaryCall + + func claimAirdrop( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> UnaryCall } extension Proto_TokenServiceClientProtocol { @@ -478,6 +503,139 @@ extension Proto_TokenServiceClientProtocol { interceptors: self.interceptors?.makeunpauseTokenInterceptors() ?? [] ) } + + ///* + /// Updates the NFTs in a collection by TokenID and serial number + /// + /// - Parameters: + /// - request: Request to send to updateNfts. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func updateNfts( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.updateNfts.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeupdateNftsInterceptors() ?? [] + ) + } + + ///* + /// Reject one or more tokens.
+ /// This transaction SHALL transfer the full balance of one or more tokens from the requesting + /// account to the treasury for each token. This transfer SHALL NOT charge any custom fee or + /// royalty defined for the token(s) to be rejected.
+ ///

Effects on success

+ ///
    + ///
  • If the rejected token is fungible/common, the requesting account SHALL have a balance + /// of 0 for the rejected token. The treasury balance SHALL increase by the amount that + /// the requesting account decreased.
  • + ///
  • If the rejected token is non-fungible/unique the requesting account SHALL NOT hold + /// the specific serialized token that is rejected. The treasury account SHALL hold each + /// specific serialized token that was rejected.
  • + /// + /// + /// - Parameters: + /// - request: Request to send to rejectToken. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func rejectToken( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.rejectToken.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makerejectTokenInterceptors() ?? [] + ) + } + + ///* + /// Airdrop one or more tokens to one or more accounts.
    + /// This distributes tokens from the balance of one or more sending account(s) to the balance + /// of one or more recipient accounts. Accounts will receive the tokens in one of four ways. + ///
      + ///
    • An account already associated to the token to be distributed SHALL receive the + /// airdropped tokens immediately to the recipient account balance.
    • + ///
    • An account with available automatic association slots SHALL be automatically + /// associated to the token, and SHALL immediately receive the airdropped tokens to the + /// recipient account balance.
    • + ///
    • An account with "receiver signature required" set SHALL have a "Pending Airdrop" + /// created and MUST claim that airdrop with a `claimAirdrop` transaction.
    • + ///
    • An account with no available automatic association slots SHALL have a + /// "Pending Airdrop" created and MUST claim that airdrop with a `claimAirdrop` + /// transaction.
    • + ///
    + /// Any airdrop that completes immediately SHALL be irreversible. Any airdrop that results in a + /// "Pending Airdrop" MAY be canceled via a `cancelAirdrop` transaction.
    + /// All transfer fees (including custom fees and royalties), as well as the rent cost for the + /// first auto-renewal period for any automatic-association slot occupied by the airdropped + /// tokens, SHALL be charged to the account submitting this transaction. + /// + /// - Parameters: + /// - request: Request to send to airdropTokens. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func airdropTokens( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.airdropTokens.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeairdropTokensInterceptors() ?? [] + ) + } + + ///* + /// Cancel one or more pending airdrops. + ///

    + /// This transaction MUST be signed by _each_ account *sending* an airdrop to be canceled. + /// + /// - Parameters: + /// - request: Request to send to cancelAirdrop. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func cancelAirdrop( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.cancelAirdrop.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makecancelAirdropInterceptors() ?? [] + ) + } + + ///* + /// Claim one or more pending airdrops. + ///

    + /// This transaction MUST be signed by _each_ account **receiving** an + /// airdrop to be claimed.
    + /// If a "Sender" lacks sufficient balance to fulfill the airdrop at the + /// time the claim is made, that claim SHALL fail. + /// + /// - Parameters: + /// - request: Request to send to claimAirdrop. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func claimAirdrop( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.claimAirdrop.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeclaimAirdropInterceptors() ?? [] + ) + } } @available(*, deprecated) @@ -638,6 +796,31 @@ public protocol Proto_TokenServiceAsyncClientProtocol: GRPCClient { _ request: Proto_Transaction, callOptions: CallOptions? ) -> GRPCAsyncUnaryCall + + func makeUpdateNftsCall( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall + + func makeRejectTokenCall( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall + + func makeAirdropTokensCall( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall + + func makeCancelAirdropCall( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall + + func makeClaimAirdropCall( + _ request: Proto_Transaction, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall } @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) @@ -877,6 +1060,66 @@ extension Proto_TokenServiceAsyncClientProtocol { interceptors: self.interceptors?.makeunpauseTokenInterceptors() ?? [] ) } + + public func makeUpdateNftsCall( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.updateNfts.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeupdateNftsInterceptors() ?? [] + ) + } + + public func makeRejectTokenCall( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.rejectToken.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makerejectTokenInterceptors() ?? [] + ) + } + + public func makeAirdropTokensCall( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.airdropTokens.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeairdropTokensInterceptors() ?? [] + ) + } + + public func makeCancelAirdropCall( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.cancelAirdrop.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makecancelAirdropInterceptors() ?? [] + ) + } + + public func makeClaimAirdropCall( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.claimAirdrop.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeclaimAirdropInterceptors() ?? [] + ) + } } @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) @@ -1108,6 +1351,66 @@ extension Proto_TokenServiceAsyncClientProtocol { interceptors: self.interceptors?.makeunpauseTokenInterceptors() ?? [] ) } + + public func updateNfts( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) async throws -> Proto_TransactionResponse { + return try await self.performAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.updateNfts.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeupdateNftsInterceptors() ?? [] + ) + } + + public func rejectToken( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) async throws -> Proto_TransactionResponse { + return try await self.performAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.rejectToken.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makerejectTokenInterceptors() ?? [] + ) + } + + public func airdropTokens( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) async throws -> Proto_TransactionResponse { + return try await self.performAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.airdropTokens.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeairdropTokensInterceptors() ?? [] + ) + } + + public func cancelAirdrop( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) async throws -> Proto_TransactionResponse { + return try await self.performAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.cancelAirdrop.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makecancelAirdropInterceptors() ?? [] + ) + } + + public func claimAirdrop( + _ request: Proto_Transaction, + callOptions: CallOptions? = nil + ) async throws -> Proto_TransactionResponse { + return try await self.performAsyncUnaryCall( + path: Proto_TokenServiceClientMetadata.Methods.claimAirdrop.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeclaimAirdropInterceptors() ?? [] + ) + } } @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) @@ -1185,6 +1488,21 @@ public protocol Proto_TokenServiceClientInterceptorFactoryProtocol: Sendable { /// - Returns: Interceptors to use when invoking 'unpauseToken'. func makeunpauseTokenInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'updateNfts'. + func makeupdateNftsInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'rejectToken'. + func makerejectTokenInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'airdropTokens'. + func makeairdropTokensInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'cancelAirdrop'. + func makecancelAirdropInterceptors() -> [ClientInterceptor] + + /// - Returns: Interceptors to use when invoking 'claimAirdrop'. + func makeclaimAirdropInterceptors() -> [ClientInterceptor] } public enum Proto_TokenServiceClientMetadata { @@ -1211,6 +1529,11 @@ public enum Proto_TokenServiceClientMetadata { Proto_TokenServiceClientMetadata.Methods.getTokenNftInfos, Proto_TokenServiceClientMetadata.Methods.pauseToken, Proto_TokenServiceClientMetadata.Methods.unpauseToken, + Proto_TokenServiceClientMetadata.Methods.updateNfts, + Proto_TokenServiceClientMetadata.Methods.rejectToken, + Proto_TokenServiceClientMetadata.Methods.airdropTokens, + Proto_TokenServiceClientMetadata.Methods.cancelAirdrop, + Proto_TokenServiceClientMetadata.Methods.claimAirdrop, ] ) @@ -1328,6 +1651,36 @@ public enum Proto_TokenServiceClientMetadata { path: "/proto.TokenService/unpauseToken", type: GRPCCallType.unary ) + + public static let updateNfts = GRPCMethodDescriptor( + name: "updateNfts", + path: "/proto.TokenService/updateNfts", + type: GRPCCallType.unary + ) + + public static let rejectToken = GRPCMethodDescriptor( + name: "rejectToken", + path: "/proto.TokenService/rejectToken", + type: GRPCCallType.unary + ) + + public static let airdropTokens = GRPCMethodDescriptor( + name: "airdropTokens", + path: "/proto.TokenService/airdropTokens", + type: GRPCCallType.unary + ) + + public static let cancelAirdrop = GRPCMethodDescriptor( + name: "cancelAirdrop", + path: "/proto.TokenService/cancelAirdrop", + type: GRPCCallType.unary + ) + + public static let claimAirdrop = GRPCMethodDescriptor( + name: "claimAirdrop", + path: "/proto.TokenService/claimAirdrop", + type: GRPCCallType.unary + ) } } diff --git a/Sources/HederaProtobufs/Services/transaction_body.pb.swift b/Sources/HederaProtobufs/Services/transaction_body.pb.swift index 2586b6b0..a16e53b5 100644 --- a/Sources/HederaProtobufs/Services/transaction_body.pb.swift +++ b/Sources/HederaProtobufs/Services/transaction_body.pb.swift @@ -615,6 +615,36 @@ public struct Proto_TransactionBody { set {_uniqueStorage()._data = .tokenReject(newValue)} } + ///* + /// A transaction body for a `tokenAirdrop` request. + public var tokenAirdrop: Proto_TokenAirdropTransactionBody { + get { + if case .tokenAirdrop(let v)? = _storage._data {return v} + return Proto_TokenAirdropTransactionBody() + } + set {_uniqueStorage()._data = .tokenAirdrop(newValue)} + } + + ///* + /// A transaction body for a `cancelAirdrop` request. + public var tokenCancelAirdrop: Proto_TokenCancelAirdropTransactionBody { + get { + if case .tokenCancelAirdrop(let v)? = _storage._data {return v} + return Proto_TokenCancelAirdropTransactionBody() + } + set {_uniqueStorage()._data = .tokenCancelAirdrop(newValue)} + } + + ///* + /// A transaction body for a `claimAirdrop` request. + public var tokenClaimAirdrop: Proto_TokenClaimAirdropTransactionBody { + get { + if case .tokenClaimAirdrop(let v)? = _storage._data {return v} + return Proto_TokenClaimAirdropTransactionBody() + } + set {_uniqueStorage()._data = .tokenClaimAirdrop(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() ///* @@ -793,6 +823,15 @@ public struct Proto_TransactionBody { /// Custom fees and royalties defined for the tokens rejected /// SHALL NOT be charged for this transaction. case tokenReject(Proto_TokenRejectTransactionBody) + ///* + /// A transaction body for a `tokenAirdrop` request. + case tokenAirdrop(Proto_TokenAirdropTransactionBody) + ///* + /// A transaction body for a `cancelAirdrop` request. + case tokenCancelAirdrop(Proto_TokenCancelAirdropTransactionBody) + ///* + /// A transaction body for a `claimAirdrop` request. + case tokenClaimAirdrop(Proto_TokenClaimAirdropTransactionBody) #if !swift(>=4.1) public static func ==(lhs: Proto_TransactionBody.OneOf_Data, rhs: Proto_TransactionBody.OneOf_Data) -> Bool { @@ -1000,6 +1039,18 @@ public struct Proto_TransactionBody { guard case .tokenReject(let l) = lhs, case .tokenReject(let r) = rhs else { preconditionFailure() } return l == r }() + case (.tokenAirdrop, .tokenAirdrop): return { + guard case .tokenAirdrop(let l) = lhs, case .tokenAirdrop(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.tokenCancelAirdrop, .tokenCancelAirdrop): return { + guard case .tokenCancelAirdrop(let l) = lhs, case .tokenCancelAirdrop(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.tokenClaimAirdrop, .tokenClaimAirdrop): return { + guard case .tokenClaimAirdrop(let l) = lhs, case .tokenClaimAirdrop(let r) = rhs else { preconditionFailure() } + return l == r + }() default: return false } } @@ -1079,6 +1130,9 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 55: .same(proto: "nodeUpdate"), 56: .same(proto: "nodeDelete"), 57: .same(proto: "tokenReject"), + 58: .same(proto: "tokenAirdrop"), + 59: .same(proto: "tokenCancelAirdrop"), + 60: .same(proto: "tokenClaimAirdrop"), ] fileprivate class _StorageClass { @@ -1784,6 +1838,45 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm _storage._data = .tokenReject(v) } }() + case 58: try { + var v: Proto_TokenAirdropTransactionBody? + var hadOneofValue = false + if let current = _storage._data { + hadOneofValue = true + if case .tokenAirdrop(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._data = .tokenAirdrop(v) + } + }() + case 59: try { + var v: Proto_TokenCancelAirdropTransactionBody? + var hadOneofValue = false + if let current = _storage._data { + hadOneofValue = true + if case .tokenCancelAirdrop(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._data = .tokenCancelAirdrop(v) + } + }() + case 60: try { + var v: Proto_TokenClaimAirdropTransactionBody? + var hadOneofValue = false + if let current = _storage._data { + hadOneofValue = true + if case .tokenClaimAirdrop(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._data = .tokenClaimAirdrop(v) + } + }() default: break } } @@ -2015,6 +2108,18 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm guard case .tokenReject(let v)? = _storage._data else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 57) }() + case .tokenAirdrop?: try { + guard case .tokenAirdrop(let v)? = _storage._data else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 58) + }() + case .tokenCancelAirdrop?: try { + guard case .tokenCancelAirdrop(let v)? = _storage._data else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 59) + }() + case .tokenClaimAirdrop?: try { + guard case .tokenClaimAirdrop(let v)? = _storage._data else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 60) + }() case nil: break } } diff --git a/Sources/HederaProtobufs/Services/transaction_record.pb.swift b/Sources/HederaProtobufs/Services/transaction_record.pb.swift index 4c42bdce..838240ae 100644 --- a/Sources/HederaProtobufs/Services/transaction_record.pb.swift +++ b/Sources/HederaProtobufs/Services/transaction_record.pb.swift @@ -225,6 +225,21 @@ public struct Proto_TransactionRecord { set {_uniqueStorage()._evmAddress = newValue} } + ///* + /// A list of pending token airdrops. + /// Each pending airdrop represents a single requested transfer from a + /// sending account to a recipient account. These pending transfers are + /// issued unilaterally by the sending account, and MUST be claimed by the + /// recipient account before the transfer MAY complete. + /// A sender MAY cancel a pending airdrop before it is claimed. + /// An airdrop transaction SHALL emit a pending airdrop when the recipient has no + /// available automatic association slots available or when the recipient + /// has set `receiver_sig_required`. + public var newPendingAirdrops: [Proto_PendingAirdropRecord] { + get {return _storage._newPendingAirdrops} + set {_uniqueStorage()._newPendingAirdrops = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Body: Equatable { @@ -290,10 +305,53 @@ public struct Proto_TransactionRecord { fileprivate var _storage = _StorageClass.defaultInstance } +///* +/// A record of a new pending airdrop. +public struct Proto_PendingAirdropRecord { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + ///* + /// A unique, composite, identifier for a pending airdrop. + /// This field is REQUIRED. + public var pendingAirdropID: Proto_PendingAirdropId { + get {return _pendingAirdropID ?? Proto_PendingAirdropId()} + set {_pendingAirdropID = newValue} + } + /// Returns true if `pendingAirdropID` has been explicitly set. + public var hasPendingAirdropID: Bool {return self._pendingAirdropID != nil} + /// Clears the value of `pendingAirdropID`. Subsequent reads from it will return its default value. + public mutating func clearPendingAirdropID() {self._pendingAirdropID = nil} + + ///* + /// A single pending airdrop amount. + /// If the pending airdrop is for a fungible/common token this field is REQUIRED + /// and SHALL be the current amount of tokens offered. + /// If the pending airdrop is for a non-fungible/unique token, this field SHALL NOT + /// be set. + public var pendingAirdropValue: Proto_PendingAirdropValue { + get {return _pendingAirdropValue ?? Proto_PendingAirdropValue()} + set {_pendingAirdropValue = newValue} + } + /// Returns true if `pendingAirdropValue` has been explicitly set. + public var hasPendingAirdropValue: Bool {return self._pendingAirdropValue != nil} + /// Clears the value of `pendingAirdropValue`. Subsequent reads from it will return its default value. + public mutating func clearPendingAirdropValue() {self._pendingAirdropValue = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _pendingAirdropID: Proto_PendingAirdropId? = nil + fileprivate var _pendingAirdropValue: Proto_PendingAirdropValue? = nil +} + #if swift(>=5.5) && canImport(_Concurrency) extension Proto_TransactionRecord: @unchecked Sendable {} extension Proto_TransactionRecord.OneOf_Body: @unchecked Sendable {} extension Proto_TransactionRecord.OneOf_Entropy: @unchecked Sendable {} +extension Proto_PendingAirdropRecord: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. @@ -323,6 +381,7 @@ extension Proto_TransactionRecord: SwiftProtobuf.Message, SwiftProtobuf._Message 19: .standard(proto: "prng_bytes"), 20: .standard(proto: "prng_number"), 21: .standard(proto: "evm_address"), + 22: .standard(proto: "new_pending_airdrops"), ] fileprivate class _StorageClass { @@ -344,6 +403,7 @@ extension Proto_TransactionRecord: SwiftProtobuf.Message, SwiftProtobuf._Message var _paidStakingRewards: [Proto_AccountAmount] = [] var _entropy: Proto_TransactionRecord.OneOf_Entropy? var _evmAddress: Data = Data() + var _newPendingAirdrops: [Proto_PendingAirdropRecord] = [] #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -376,6 +436,7 @@ extension Proto_TransactionRecord: SwiftProtobuf.Message, SwiftProtobuf._Message _paidStakingRewards = source._paidStakingRewards _entropy = source._entropy _evmAddress = source._evmAddress + _newPendingAirdrops = source._newPendingAirdrops } } @@ -452,6 +513,7 @@ extension Proto_TransactionRecord: SwiftProtobuf.Message, SwiftProtobuf._Message } }() case 21: try { try decoder.decodeSingularBytesField(value: &_storage._evmAddress) }() + case 22: try { try decoder.decodeRepeatedMessageField(value: &_storage._newPendingAirdrops) }() default: break } } @@ -534,6 +596,9 @@ extension Proto_TransactionRecord: SwiftProtobuf.Message, SwiftProtobuf._Message if !_storage._evmAddress.isEmpty { try visitor.visitSingularBytesField(value: _storage._evmAddress, fieldNumber: 21) } + if !_storage._newPendingAirdrops.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._newPendingAirdrops, fieldNumber: 22) + } } try unknownFields.traverse(visitor: &visitor) } @@ -561,6 +626,7 @@ extension Proto_TransactionRecord: SwiftProtobuf.Message, SwiftProtobuf._Message if _storage._paidStakingRewards != rhs_storage._paidStakingRewards {return false} if _storage._entropy != rhs_storage._entropy {return false} if _storage._evmAddress != rhs_storage._evmAddress {return false} + if _storage._newPendingAirdrops != rhs_storage._newPendingAirdrops {return false} return true } if !storagesAreEqual {return false} @@ -569,3 +635,45 @@ extension Proto_TransactionRecord: SwiftProtobuf.Message, SwiftProtobuf._Message return true } } + +extension Proto_PendingAirdropRecord: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".PendingAirdropRecord" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "pending_airdrop_id"), + 2: .standard(proto: "pending_airdrop_value"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &self._pendingAirdropID) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._pendingAirdropValue) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._pendingAirdropID { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = self._pendingAirdropValue { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_PendingAirdropRecord, rhs: Proto_PendingAirdropRecord) -> Bool { + if lhs._pendingAirdropID != rhs._pendingAirdropID {return false} + if lhs._pendingAirdropValue != rhs._pendingAirdropValue {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/HederaTCK/SDKClient.swift b/Sources/HederaTCK/SDKClient.swift index 95cc4511..410c08c2 100644 --- a/Sources/HederaTCK/SDKClient.swift +++ b/Sources/HederaTCK/SDKClient.swift @@ -46,7 +46,7 @@ internal class SDKClient { do { return Key.single(try PublicKey.fromStringDer(key)) } catch { - return try Key(protobuf: try Proto_Key(serializedData: Data(hex: key))) + return try Key(protobuf: try Proto_Key(serializedBytes: Data(hex: key))) } } } diff --git a/Sources/HederaTCK/main.swift b/Sources/HederaTCK/main.swift index a4d83bf8..ee0ffcb3 100644 --- a/Sources/HederaTCK/main.swift +++ b/Sources/HederaTCK/main.swift @@ -97,9 +97,9 @@ private struct TCKServer { return JSONResponse(id: request.id, error: error) } catch let error as HError { switch error.kind { - case .transactionPreCheckStatus(let status, let _), - .queryPreCheckStatus(let status, let _), - .receiptStatus(let status, let _): + case .transactionPreCheckStatus(let status, _), + .queryPreCheckStatus(let status, _), + .receiptStatus(let status, _): return JSONResponse( id: request.id, error: JSONError.hederaError( diff --git a/Tests/HederaTests/FileAppendTransactionTests.swift b/Tests/HederaTests/FileAppendTransactionTests.swift index 7c148a50..23a63290 100644 --- a/Tests/HederaTests/FileAppendTransactionTests.swift +++ b/Tests/HederaTests/FileAppendTransactionTests.swift @@ -45,7 +45,7 @@ internal final class FileAppendTransactionTests: XCTestCase { // Unlike most transactions, this iteration makes sure the chunked data is properly handled. // NOTE: Without a client, dealing with chunked data is cumbersome. let bodyBytes = try tx.makeSources().signedTransactions.makeIterator().map { signed in - try Proto_TransactionBody.init(contiguousBytes: signed.bodyBytes) + try Proto_TransactionBody.init(serializedBytes: signed.bodyBytes) } let txes = try bodyBytes.makeIterator().map { bytes in @@ -62,11 +62,11 @@ internal final class FileAppendTransactionTests: XCTestCase { // As stated above, this assignment properly handles the possibilty of the data being chunked. let txBody = try tx.makeSources().signedTransactions.makeIterator().map { signed in - try Proto_TransactionBody.init(contiguousBytes: signed.bodyBytes) + try Proto_TransactionBody.init(serializedBytes: signed.bodyBytes) } let txBody2 = try tx2.makeSources().signedTransactions.makeIterator().map { signed in - try Proto_TransactionBody.init(contiguousBytes: signed.bodyBytes) + try Proto_TransactionBody.init(serializedBytes: signed.bodyBytes) } XCTAssertEqual(txBody, txBody2) diff --git a/Tests/HederaTests/KeyTests.swift b/Tests/HederaTests/KeyTests.swift index 662e2637..7012ead0 100644 --- a/Tests/HederaTests/KeyTests.swift +++ b/Tests/HederaTests/KeyTests.swift @@ -40,7 +40,7 @@ internal final class KeyTests: XCTestCase { internal func testFromProtoKeyEcdsa() throws { let keyBytes = Data(hex: "3a21034e0441201f2bf9c7d9873c2a9dc3fd451f64b7c05e17e4d781d916e3a11dfd99") - let keyProto = try Proto_Key.init(serializedData: keyBytes) + let keyProto = try Proto_Key.init(serializedBytes: keyBytes) let key = try PublicKey.fromProtobuf(keyProto) diff --git a/Tests/HederaTests/NodeCreateTransactionTests.swift b/Tests/HederaTests/NodeCreateTransactionTests.swift new file mode 100644 index 00000000..e3a342c0 --- /dev/null +++ b/Tests/HederaTests/NodeCreateTransactionTests.swift @@ -0,0 +1,171 @@ +/* + * ‌ + * Hedera Swift SDK + * ​ + * Copyright (C) 2023 - 2024 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +import HederaProtobufs +import Network +import SnapshotTesting +import XCTest + +@testable import Hedera + +internal final class NodeCreateTransactionTests: XCTestCase { + internal static let testDescription = "test description" + internal static let testGossipCertificate = Data([0x01, 0x02, 0x03, 0x04]) + internal static let testGrpcCertificateHash = Data([0x05, 0x06, 0x07, 0x08]) + + private static func spawnTestEndpoint(offset: Int32) -> Endpoint { + Endpoint(ipAddress: IPv4Address("127.0.0.1:50222"), port: 42 + offset, domainName: "unit.test.com") + } + + private static func spawnTestEndpointList(offset: Int32) -> [Endpoint] { + [Self.spawnTestEndpoint(offset: offset), Self.spawnTestEndpoint(offset: offset + 1)] + } + + private static func makeTransaction() throws -> NodeCreateTransaction { + try NodeCreateTransaction() + .nodeAccountIds([AccountId("0.0.5005"), AccountId("0.0.5006")]) + .transactionId( + TransactionId( + accountId: 5005, validStart: Timestamp(seconds: 1_554_158_542, subSecondNanos: 0), scheduled: false) + ) + .accountId(AccountId.fromString("0.0.5007")) + .description(testDescription) + .gossipEndpoints(spawnTestEndpointList(offset: 0)) + .serviceEndpoints(spawnTestEndpointList(offset: 2)) + .gossipCaCertificate(Self.testGossipCertificate) + .grpcCertificateHash(Self.testGrpcCertificateHash) + .adminKey(Key.single(Resources.privateKey.publicKey)) + .freeze() + .sign(Resources.privateKey) + } + + internal func testSerialize() throws { + let tx = try Self.makeTransaction().makeProtoBody() + + assertSnapshot(matching: tx, as: .description) + } + + internal func testToFromBytes() throws { + let tx = try Self.makeTransaction() + let tx2 = try Transaction.fromBytes(tx.toBytes()) + + XCTAssertEqual(try tx.makeProtoBody(), try tx2.makeProtoBody()) + } + + internal func testFromProtoBody() throws { + let gossipEndpoints = Self.spawnTestEndpointList(offset: 0) + let serviceEndpoints = Self.spawnTestEndpointList(offset: 2) + let protoData = Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody.with { proto in + proto.accountID = Resources.accountId.toProtobuf() + proto.description_p = Self.testDescription + proto.gossipEndpoint = gossipEndpoints.map { $0.toProtobuf() } + proto.serviceEndpoint = serviceEndpoints.map { $0.toProtobuf() } + proto.gossipCaCertificate = Self.testGossipCertificate + proto.grpcCertificateHash = Self.testGrpcCertificateHash + proto.adminKey = Key.single(Resources.publicKey).toProtobuf() + } + + let protoBody = Proto_TransactionBody.with { proto in + proto.nodeCreate = protoData + proto.transactionID = Resources.txId.toProtobuf() + } + + let tx = try NodeCreateTransaction(protobuf: protoBody, protoData) + + XCTAssertEqual(tx.accountId, Resources.accountId) + XCTAssertEqual(tx.adminKey, Key.single(Resources.publicKey)) + XCTAssertEqual(tx.description, Self.testDescription) + XCTAssertEqual(tx.gossipCaCertificate, Self.testGossipCertificate) + XCTAssertEqual(tx.grpcCertificateHash, Self.testGrpcCertificateHash) + XCTAssertEqual(tx.gossipEndpoints.count, 2) + XCTAssertEqual(tx.serviceEndpoints.count, 2) + + for (index, endpoint) in tx.gossipEndpoints.enumerated() { + XCTAssertEqual(endpoint.ipAddress, gossipEndpoints[index].ipAddress) + XCTAssertEqual(endpoint.port, gossipEndpoints[index].port) + XCTAssertEqual(endpoint.domainName, gossipEndpoints[index].domainName) + } + + for (index, endpoint) in tx.serviceEndpoints.enumerated() { + XCTAssertEqual(endpoint.ipAddress, serviceEndpoints[index].ipAddress) + XCTAssertEqual(endpoint.port, serviceEndpoints[index].port) + XCTAssertEqual(endpoint.domainName, serviceEndpoints[index].domainName) + } + } + + internal func testGetSetAccountId() throws { + let tx = NodeCreateTransaction() + tx.accountId(Resources.accountId) + + XCTAssertEqual(tx.accountId, Resources.accountId) + } + + internal func testGetSetAdminKey() throws { + let tx = NodeCreateTransaction() + tx.adminKey(.single(Resources.publicKey)) + + XCTAssertEqual(tx.adminKey, .single(Resources.publicKey)) + } + + internal func testGetSetDescription() throws { + let tx = NodeCreateTransaction() + tx.description(Self.testDescription) + + XCTAssertEqual(tx.description, Self.testDescription) + } + + internal func testGetSetGossipEndpoints() throws { + let tx = NodeCreateTransaction() + let endpoints = Self.spawnTestEndpointList(offset: Int32(0)) + tx.gossipEndpoints(endpoints) + + for (index, endpoint) in tx.gossipEndpoints.enumerated() { + XCTAssertEqual(endpoint.ipAddress, endpoints[index].ipAddress) + XCTAssertEqual(endpoint.port, endpoints[index].port) + XCTAssertEqual(endpoint.domainName, endpoints[index].domainName) + } + } + + internal func testGetSetServiceEndpoints() throws { + let tx = NodeCreateTransaction() + let endpoints = Self.spawnTestEndpointList(offset: Int32(2)) + tx.serviceEndpoints(endpoints) + + for (index, endpoint) in tx.serviceEndpoints.enumerated() { + XCTAssertEqual(endpoint.ipAddress, endpoints[index].ipAddress) + XCTAssertEqual(endpoint.port, endpoints[index].port) + XCTAssertEqual(endpoint.domainName, endpoints[index].domainName) + } + } + + internal func testGetSetGossipCaCertificate() throws { + let tx = NodeCreateTransaction() + tx.gossipCaCertificate(Self.testGossipCertificate) + + XCTAssertEqual(tx.gossipCaCertificate, Self.testGossipCertificate) + } + + internal func testGetSetGrpcCertificateHash() throws { + let tx = NodeCreateTransaction() + tx.grpcCertificateHash(Self.testGrpcCertificateHash) + + XCTAssertEqual(tx.grpcCertificateHash, Self.testGrpcCertificateHash) + } +} diff --git a/Tests/HederaTests/NodeDeleteTransactionTests.swift b/Tests/HederaTests/NodeDeleteTransactionTests.swift new file mode 100644 index 00000000..c573e9fc --- /dev/null +++ b/Tests/HederaTests/NodeDeleteTransactionTests.swift @@ -0,0 +1,75 @@ +/* + * ‌ + * Hedera Swift SDK + * ​ + * Copyright (C) 2023 - 2024 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +import HederaProtobufs +import SnapshotTesting +import SwiftProtobuf +import XCTest + +@testable import Hedera + +internal final class NodeDeleteTransactionTests: XCTestCase { + private static func makeTransaction() throws -> NodeDeleteTransaction { + try NodeDeleteTransaction() + .nodeAccountIds([AccountId("0.0.5005"), AccountId("0.0.5006")]) + .transactionId( + TransactionId( + accountId: 5005, validStart: Timestamp(seconds: 1_554_158_542, subSecondNanos: 0), scheduled: false) + ) + .nodeId(2) + .freeze() + .sign(Resources.privateKey) + } + + internal func testSerialize() throws { + let tx = try Self.makeTransaction().makeProtoBody() + + assertSnapshot(matching: tx, as: .description) + } + + internal func testToFromBytes() throws { + let tx = try Self.makeTransaction() + let tx2 = try Transaction.fromBytes(tx.toBytes()) + + XCTAssertEqual(try tx.makeProtoBody(), try tx2.makeProtoBody()) + } + + internal func testFromProtoBody() throws { + let protoData = Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody.with { proto in + proto.nodeID = 2 + } + + let protoBody = Proto_TransactionBody.with { proto in + proto.nodeDelete = protoData + proto.transactionID = Resources.txId.toProtobuf() + } + + let tx = try NodeDeleteTransaction(protobuf: protoBody, protoData) + + XCTAssertEqual(tx.nodeId, 2) + } + + internal func testGetSetNodeId() throws { + let tx = NodeDeleteTransaction() + tx.nodeId(2) + + XCTAssertEqual(tx.nodeId, 2) + } +} diff --git a/Tests/HederaTests/NodeUpdateTransactionTests.swift b/Tests/HederaTests/NodeUpdateTransactionTests.swift new file mode 100644 index 00000000..a7669a5b --- /dev/null +++ b/Tests/HederaTests/NodeUpdateTransactionTests.swift @@ -0,0 +1,181 @@ +/* + * ‌ + * Hedera Swift SDK + * ​ + * Copyright (C) 2023 - 2024 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +import HederaProtobufs +import Network +import SnapshotTesting +import SwiftProtobuf +import XCTest + +@testable import Hedera + +internal final class NodeUpdateTransactionTests: XCTestCase { + internal static let testDescription = "test description" + internal static let testGossipCertificate = Data([0x01, 0x02, 0x03, 0x04]) + internal static let testGrpcCertificateHash = Data([0x05, 0x06, 0x07, 0x08]) + + private static func spawnTestEndpoint(offset: Int32) -> Endpoint { + Endpoint(ipAddress: IPv4Address("127.0.0.1:50211"), port: 20 + offset, domainName: "unit.test.com") + } + + private static func spawnTestEndpointList(offset: Int32) -> [Endpoint] { + [Self.spawnTestEndpoint(offset: offset), Self.spawnTestEndpoint(offset: offset + 1)] + } + + private static func makeTransaction() throws -> NodeUpdateTransaction { + try NodeUpdateTransaction() + .nodeId(1) + .nodeAccountIds([AccountId("0.0.5005"), AccountId("0.0.5006")]) + .transactionId( + TransactionId( + accountId: 5005, validStart: Timestamp(seconds: 1_554_158_542, subSecondNanos: 0), scheduled: false) + ) + .accountId(AccountId.fromString("0.0.5007")) + .description(testDescription) + .gossipEndpoints(Self.spawnTestEndpointList(offset: 1)) + .serviceEndpoints(Self.spawnTestEndpointList(offset: 3)) + .gossipCaCertificate(Self.testGossipCertificate) + .grpcCertificateHash(Self.testGrpcCertificateHash) + .adminKey(Key.single(Resources.privateKey.publicKey)) + .freeze() + .sign(Resources.privateKey) + } + + internal func testSerialize() throws { + let tx = try Self.makeTransaction().makeProtoBody() + + assertSnapshot(matching: tx, as: .description) + } + + internal func testToFromBytes() throws { + let tx = try Self.makeTransaction() + let tx2 = try Transaction.fromBytes(tx.toBytes()) + + XCTAssertEqual(try tx.makeProtoBody(), try tx2.makeProtoBody()) + } + + internal func testFromProtoBody() throws { + let gossipEndpoints = Self.spawnTestEndpointList(offset: 1) + let serviceEndpoints = Self.spawnTestEndpointList(offset: 3) + let protoData = Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody.with { proto in + proto.accountID = Resources.accountId.toProtobuf() + proto.description_p = Google_Protobuf_StringValue(Self.testDescription) + proto.gossipEndpoint = gossipEndpoints.map { $0.toProtobuf() } + proto.serviceEndpoint = serviceEndpoints.map { $0.toProtobuf() } + proto.gossipCaCertificate = Google_Protobuf_BytesValue(Self.testGossipCertificate) + proto.grpcCertificateHash = Google_Protobuf_BytesValue(Self.testGrpcCertificateHash) + proto.adminKey = Key.single(Resources.publicKey).toProtobuf() + } + + let protoBody = Proto_TransactionBody.with { proto in + proto.nodeUpdate = protoData + proto.transactionID = Resources.txId.toProtobuf() + } + + let tx = try NodeUpdateTransaction(protobuf: protoBody, protoData) + + XCTAssertEqual(tx.nodeId, 0) + XCTAssertEqual(tx.accountId, Resources.accountId) + XCTAssertEqual(tx.adminKey, Key.single(Resources.publicKey)) + XCTAssertEqual(tx.description, Self.testDescription) + XCTAssertEqual(tx.gossipCaCertificate, Self.testGossipCertificate) + XCTAssertEqual(tx.grpcCertificateHash, Self.testGrpcCertificateHash) + XCTAssertEqual(tx.gossipEndpoints.count, 2) + XCTAssertEqual(tx.serviceEndpoints.count, 2) + + for (index, endpoint) in tx.gossipEndpoints.enumerated() { + XCTAssertEqual(endpoint.ipAddress, gossipEndpoints[index].ipAddress) + XCTAssertEqual(endpoint.port, gossipEndpoints[index].port) + XCTAssertEqual(endpoint.domainName, gossipEndpoints[index].domainName) + } + + for (index, endpoint) in tx.serviceEndpoints.enumerated() { + XCTAssertEqual(endpoint.ipAddress, serviceEndpoints[index].ipAddress) + XCTAssertEqual(endpoint.port, serviceEndpoints[index].port) + XCTAssertEqual(endpoint.domainName, serviceEndpoints[index].domainName) + } + } + + internal func testGetSetNodeId() throws { + let tx = NodeUpdateTransaction() + tx.nodeId(1) + + XCTAssertEqual(tx.nodeId, 1) + } + + internal func testGetSetAccountId() throws { + let tx = NodeUpdateTransaction() + tx.accountId(Resources.accountId) + + XCTAssertEqual(tx.accountId, Resources.accountId) + } + + internal func testGetSetAdminKey() throws { + let tx = NodeUpdateTransaction() + tx.adminKey(.single(Resources.publicKey)) + + XCTAssertEqual(tx.adminKey, .single(Resources.publicKey)) + } + + internal func testGetSetDescription() throws { + let tx = NodeUpdateTransaction() + tx.description(Self.testDescription) + + XCTAssertEqual(tx.description, Self.testDescription) + } + + internal func testGetSetGossipEndpoints() throws { + let tx = NodeUpdateTransaction() + let endpoints = Self.spawnTestEndpointList(offset: Int32(4)) + tx.gossipEndpoints(endpoints) + + for (index, endpoint) in tx.gossipEndpoints.enumerated() { + XCTAssertEqual(endpoint.ipAddress, endpoints[index].ipAddress) + XCTAssertEqual(endpoint.port, endpoints[index].port) + XCTAssertEqual(endpoint.domainName, endpoints[index].domainName) + } + } + + internal func testGetSetServiceEndpoints() throws { + let tx = NodeUpdateTransaction() + let endpoints = Self.spawnTestEndpointList(offset: Int32(4)) + tx.serviceEndpoints(endpoints) + + for (index, endpoint) in tx.serviceEndpoints.enumerated() { + XCTAssertEqual(endpoint.ipAddress, endpoints[index].ipAddress) + XCTAssertEqual(endpoint.port, endpoints[index].port) + XCTAssertEqual(endpoint.domainName, endpoints[index].domainName) + } + } + + internal func testGetSetGossipCaCertificate() throws { + let tx = NodeUpdateTransaction() + tx.gossipCaCertificate(Self.testGossipCertificate) + + XCTAssertEqual(tx.gossipCaCertificate, Self.testGossipCertificate) + } + + internal func testGetSetGrpcCertificateHash() throws { + let tx = NodeUpdateTransaction() + tx.grpcCertificateHash(Self.testGrpcCertificateHash) + + XCTAssertEqual(tx.grpcCertificateHash, Self.testGrpcCertificateHash) + } +} diff --git a/Tests/HederaTests/Transaction+Extensions.swift b/Tests/HederaTests/Transaction+Extensions.swift index 0f9da2d9..fc1623fa 100644 --- a/Tests/HederaTests/Transaction+Extensions.swift +++ b/Tests/HederaTests/Transaction+Extensions.swift @@ -26,6 +26,6 @@ import XCTest extension Transaction { internal func makeProtoBody() throws -> Proto_TransactionBody { - try Proto_TransactionBody(contiguousBytes: makeSources().signedTransactions[0].bodyBytes) + try Proto_TransactionBody(serializedBytes: makeSources().signedTransactions[0].bodyBytes) } } diff --git a/Tests/HederaTests/__Snapshots__/NodeCreateTransactionTests/testSerialize.1.txt b/Tests/HederaTests/__Snapshots__/NodeCreateTransactionTests/testSerialize.1.txt new file mode 100644 index 00000000..5c49d95a --- /dev/null +++ b/Tests/HederaTests/__Snapshots__/NodeCreateTransactionTests/testSerialize.1.txt @@ -0,0 +1,43 @@ +HederaProtobufs.Proto_TransactionBody: +transactionID { + transactionValidStart { + seconds: 1554158542 + } + accountID { + accountNum: 5005 + } +} +nodeAccountID { + accountNum: 5005 +} +transactionFee: 200000000 +transactionValidDuration { + seconds: 120 +} +nodeCreate { + account_id { + accountNum: 5007 + } + description: "test description" + gossip_endpoint { + port: 42 + domain_name: "unit.test.com" + } + gossip_endpoint { + port: 43 + domain_name: "unit.test.com" + } + service_endpoint { + port: 44 + domain_name: "unit.test.com" + } + service_endpoint { + port: 45 + domain_name: "unit.test.com" + } + gossip_ca_certificate: "\001\002\003\004" + grpc_certificate_hash: "\005\006\007\b" + admin_key { + ed25519: "\340\310\354'X\245\207\237\372\302&\241<\fQky\236r\343QA\240\335\202\217\224\323y\210\244\267" + } +} diff --git a/Tests/HederaTests/__Snapshots__/NodeDeleteTransactionTests/testSerialize.1.txt b/Tests/HederaTests/__Snapshots__/NodeDeleteTransactionTests/testSerialize.1.txt new file mode 100644 index 00000000..b94fc04d --- /dev/null +++ b/Tests/HederaTests/__Snapshots__/NodeDeleteTransactionTests/testSerialize.1.txt @@ -0,0 +1,19 @@ +HederaProtobufs.Proto_TransactionBody: +transactionID { + transactionValidStart { + seconds: 1554158542 + } + accountID { + accountNum: 5005 + } +} +nodeAccountID { + accountNum: 5005 +} +transactionFee: 200000000 +transactionValidDuration { + seconds: 120 +} +nodeDelete { + node_id: 2 +} diff --git a/Tests/HederaTests/__Snapshots__/NodeUpdateTransactionTests/testSerialize.1.txt b/Tests/HederaTests/__Snapshots__/NodeUpdateTransactionTests/testSerialize.1.txt new file mode 100644 index 00000000..1978d25a --- /dev/null +++ b/Tests/HederaTests/__Snapshots__/NodeUpdateTransactionTests/testSerialize.1.txt @@ -0,0 +1,50 @@ +HederaProtobufs.Proto_TransactionBody: +transactionID { + transactionValidStart { + seconds: 1554158542 + } + accountID { + accountNum: 5005 + } +} +nodeAccountID { + accountNum: 5005 +} +transactionFee: 200000000 +transactionValidDuration { + seconds: 120 +} +nodeUpdate { + node_id: 1 + account_id { + accountNum: 5007 + } + description { + value: "test description" + } + gossip_endpoint { + port: 21 + domain_name: "unit.test.com" + } + gossip_endpoint { + port: 22 + domain_name: "unit.test.com" + } + service_endpoint { + port: 23 + domain_name: "unit.test.com" + } + service_endpoint { + port: 24 + domain_name: "unit.test.com" + } + gossip_ca_certificate { + value: "\001\002\003\004" + } + grpc_certificate_hash { + value: "\005\006\007\b" + } + admin_key { + ed25519: "\340\310\354'X\245\207\237\372\302&\241<\fQky\236r\343QA\240\335\202\217\224\323y\210\244\267" + } +} diff --git a/Tests/HederaTests/__Snapshots__/TransactionReceiptTests/testSerialize.1.txt b/Tests/HederaTests/__Snapshots__/TransactionReceiptTests/testSerialize.1.txt index ae725585..51c91f8f 100644 --- a/Tests/HederaTests/__Snapshots__/TransactionReceiptTests/testSerialize.1.txt +++ b/Tests/HederaTests/__Snapshots__/TransactionReceiptTests/testSerialize.1.txt @@ -1 +1 @@ -TransactionReceipt(transactionId: nil, status: SCHEDULE_ALREADY_DELETED, accountId: Optional(1.2.3), fileId: Optional(4.5.6), contractId: Optional(3.2.1), topicId: Optional(9.8.7), topicSequenceNumber: 3, topicRunningHash: Optional(12 bytes), topicRunningHashVersion: 0, tokenId: Optional(6.5.4), totalSupply: 30, scheduleId: Optional(1.1.1), exchangeRates: nil, scheduledTransactionId: Optional(0.0.5006@1554158542.0), serials: Optional([1, 2, 3]), duplicates: [], children: []) \ No newline at end of file +TransactionReceipt(transactionId: nil, status: SCHEDULE_ALREADY_DELETED, accountId: Optional(1.2.3), fileId: Optional(4.5.6), contractId: Optional(3.2.1), topicId: Optional(9.8.7), topicSequenceNumber: 3, topicRunningHash: Optional(12 bytes), topicRunningHashVersion: 0, tokenId: Optional(6.5.4), totalSupply: 30, scheduleId: Optional(1.1.1), exchangeRates: nil, scheduledTransactionId: Optional(0.0.5006@1554158542.0), serials: Optional([1, 2, 3]), duplicates: [], children: [], nodeId: 0) \ No newline at end of file diff --git a/Tests/HederaTests/__Snapshots__/TransactionRecordTests/testSerialize.1.txt b/Tests/HederaTests/__Snapshots__/TransactionRecordTests/testSerialize.1.txt index 04c68c8d..cc679f92 100644 --- a/Tests/HederaTests/__Snapshots__/TransactionRecordTests/testSerialize.1.txt +++ b/Tests/HederaTests/__Snapshots__/TransactionRecordTests/testSerialize.1.txt @@ -1 +1 @@ -TransactionRecord(receipt: Hedera.TransactionReceipt(transactionId: nil, status: SCHEDULE_ALREADY_DELETED, accountId: Optional(1.2.3), fileId: Optional(4.5.6), contractId: Optional(3.2.1), topicId: Optional(9.8.7), topicSequenceNumber: 3, topicRunningHash: Optional(12 bytes), topicRunningHashVersion: 0, tokenId: Optional(6.5.4), totalSupply: 30, scheduleId: Optional(1.1.1), exchangeRates: nil, scheduledTransactionId: Optional(0.0.5006@1554158542.0), serials: Optional([1, 2, 3]), duplicates: [], children: []), transactionHash: 5 bytes, consensusTimestamp: 1554158542000000000, contractFunctionResult: Optional(Hedera.ContractFunctionResult(contractId: 1.2.3, evmAddress: nil, errorMessage: nil, bloom: 0 bytes, gasUsed: 0, gas: 0, logs: [], hbarAmount: 0 tℏ, contractFunctionParametersBytes: 0 bytes, bytes: 0 bytes, senderAccountId: nil, contractNonces: [], signerNonce: nil)), transfers: [Hedera.Transfer(accountId: 4.4.4, amount: 5 ℏ)], tokenTransfers: [6.6.6: [1.1.1: 4]], tokenNftTransfers: [4.4.4: [Hedera.TokenNftTransfer(tokenId: 4.4.4, sender: 1.2.3, receiver: 3.2.1, serial: 4, isApproved: true)]], transactionId: 3.3.3@1554158542.0, transactionMemo: "flook", transactionFee: 3000 ℏ, scheduleRef: Optional(3.3.3), assessedCustomFees: [Hedera.AssessedCustomFee(amount: 4, tokenId: Optional(4.5.6), feeCollectorAccountId: Optional(8.6.5), payerAccountIdList: [3.3.3])], automaticTokenAssociations: [Hedera.TokenAssociation(tokenId: 5.4.3, accountId: 3.6.7)], parentConsensusTimestamp: Optional(1554158542000000000), aliasKey: Optional(302a300506032b6570032100e0c8ec2758a5879ffac226a13c0c516b799e72e35141a0dd828f94d37988a4b7), children: [], duplicates: [], ethereumHash: 14 bytes, evmAddress: Optional(0x3078303030303030303030303030303030303030), prngBytes: Optional(17 bytes), prngNumber: nil) \ No newline at end of file +TransactionRecord(receipt: Hedera.TransactionReceipt(transactionId: nil, status: SCHEDULE_ALREADY_DELETED, accountId: Optional(1.2.3), fileId: Optional(4.5.6), contractId: Optional(3.2.1), topicId: Optional(9.8.7), topicSequenceNumber: 3, topicRunningHash: Optional(12 bytes), topicRunningHashVersion: 0, tokenId: Optional(6.5.4), totalSupply: 30, scheduleId: Optional(1.1.1), exchangeRates: nil, scheduledTransactionId: Optional(0.0.5006@1554158542.0), serials: Optional([1, 2, 3]), duplicates: [], children: [], nodeId: 0), transactionHash: 5 bytes, consensusTimestamp: 1554158542000000000, contractFunctionResult: Optional(Hedera.ContractFunctionResult(contractId: 1.2.3, evmAddress: nil, errorMessage: nil, bloom: 0 bytes, gasUsed: 0, gas: 0, logs: [], hbarAmount: 0 tℏ, contractFunctionParametersBytes: 0 bytes, bytes: 0 bytes, senderAccountId: nil, contractNonces: [], signerNonce: nil)), transfers: [Hedera.Transfer(accountId: 4.4.4, amount: 5 ℏ)], tokenTransfers: [6.6.6: [1.1.1: 4]], tokenNftTransfers: [4.4.4: [Hedera.TokenNftTransfer(tokenId: 4.4.4, sender: 1.2.3, receiver: 3.2.1, serial: 4, isApproved: true)]], transactionId: 3.3.3@1554158542.0, transactionMemo: "flook", transactionFee: 3000 ℏ, scheduleRef: Optional(3.3.3), assessedCustomFees: [Hedera.AssessedCustomFee(amount: 4, tokenId: Optional(4.5.6), feeCollectorAccountId: Optional(8.6.5), payerAccountIdList: [3.3.3])], automaticTokenAssociations: [Hedera.TokenAssociation(tokenId: 5.4.3, accountId: 3.6.7)], parentConsensusTimestamp: Optional(1554158542000000000), aliasKey: Optional(302a300506032b6570032100e0c8ec2758a5879ffac226a13c0c516b799e72e35141a0dd828f94d37988a4b7), children: [], duplicates: [], ethereumHash: 14 bytes, evmAddress: Optional(0x3078303030303030303030303030303030303030), prngBytes: Optional(17 bytes), prngNumber: nil) \ No newline at end of file diff --git a/Tests/HederaTests/__Snapshots__/TransactionRecordTests/testSerialize2.1.txt b/Tests/HederaTests/__Snapshots__/TransactionRecordTests/testSerialize2.1.txt index 19077efd..578d36fc 100644 --- a/Tests/HederaTests/__Snapshots__/TransactionRecordTests/testSerialize2.1.txt +++ b/Tests/HederaTests/__Snapshots__/TransactionRecordTests/testSerialize2.1.txt @@ -1 +1 @@ -TransactionRecord(receipt: Hedera.TransactionReceipt(transactionId: nil, status: SCHEDULE_ALREADY_DELETED, accountId: Optional(1.2.3), fileId: Optional(4.5.6), contractId: Optional(3.2.1), topicId: Optional(9.8.7), topicSequenceNumber: 3, topicRunningHash: Optional(12 bytes), topicRunningHashVersion: 0, tokenId: Optional(6.5.4), totalSupply: 30, scheduleId: Optional(1.1.1), exchangeRates: nil, scheduledTransactionId: Optional(0.0.5006@1554158542.0), serials: Optional([1, 2, 3]), duplicates: [], children: []), transactionHash: 5 bytes, consensusTimestamp: 1554158542000000000, contractFunctionResult: Optional(Hedera.ContractFunctionResult(contractId: 1.2.3, evmAddress: nil, errorMessage: nil, bloom: 0 bytes, gasUsed: 0, gas: 0, logs: [], hbarAmount: 0 tℏ, contractFunctionParametersBytes: 0 bytes, bytes: 0 bytes, senderAccountId: nil, contractNonces: [], signerNonce: nil)), transfers: [Hedera.Transfer(accountId: 4.4.4, amount: 5 ℏ)], tokenTransfers: [6.6.6: [1.1.1: 4]], tokenNftTransfers: [4.4.4: [Hedera.TokenNftTransfer(tokenId: 4.4.4, sender: 1.2.3, receiver: 3.2.1, serial: 4, isApproved: true)]], transactionId: 3.3.3@1554158542.0, transactionMemo: "flook", transactionFee: 3000 ℏ, scheduleRef: Optional(3.3.3), assessedCustomFees: [Hedera.AssessedCustomFee(amount: 4, tokenId: Optional(4.5.6), feeCollectorAccountId: Optional(8.6.5), payerAccountIdList: [3.3.3])], automaticTokenAssociations: [Hedera.TokenAssociation(tokenId: 5.4.3, accountId: 3.6.7)], parentConsensusTimestamp: Optional(1554158542000000000), aliasKey: Optional(302a300506032b6570032100e0c8ec2758a5879ffac226a13c0c516b799e72e35141a0dd828f94d37988a4b7), children: [], duplicates: [], ethereumHash: 14 bytes, evmAddress: Optional(0x3078303030303030303030303030303030303030), prngBytes: nil, prngNumber: Optional(4)) \ No newline at end of file +TransactionRecord(receipt: Hedera.TransactionReceipt(transactionId: nil, status: SCHEDULE_ALREADY_DELETED, accountId: Optional(1.2.3), fileId: Optional(4.5.6), contractId: Optional(3.2.1), topicId: Optional(9.8.7), topicSequenceNumber: 3, topicRunningHash: Optional(12 bytes), topicRunningHashVersion: 0, tokenId: Optional(6.5.4), totalSupply: 30, scheduleId: Optional(1.1.1), exchangeRates: nil, scheduledTransactionId: Optional(0.0.5006@1554158542.0), serials: Optional([1, 2, 3]), duplicates: [], children: [], nodeId: 0), transactionHash: 5 bytes, consensusTimestamp: 1554158542000000000, contractFunctionResult: Optional(Hedera.ContractFunctionResult(contractId: 1.2.3, evmAddress: nil, errorMessage: nil, bloom: 0 bytes, gasUsed: 0, gas: 0, logs: [], hbarAmount: 0 tℏ, contractFunctionParametersBytes: 0 bytes, bytes: 0 bytes, senderAccountId: nil, contractNonces: [], signerNonce: nil)), transfers: [Hedera.Transfer(accountId: 4.4.4, amount: 5 ℏ)], tokenTransfers: [6.6.6: [1.1.1: 4]], tokenNftTransfers: [4.4.4: [Hedera.TokenNftTransfer(tokenId: 4.4.4, sender: 1.2.3, receiver: 3.2.1, serial: 4, isApproved: true)]], transactionId: 3.3.3@1554158542.0, transactionMemo: "flook", transactionFee: 3000 ℏ, scheduleRef: Optional(3.3.3), assessedCustomFees: [Hedera.AssessedCustomFee(amount: 4, tokenId: Optional(4.5.6), feeCollectorAccountId: Optional(8.6.5), payerAccountIdList: [3.3.3])], automaticTokenAssociations: [Hedera.TokenAssociation(tokenId: 5.4.3, accountId: 3.6.7)], parentConsensusTimestamp: Optional(1554158542000000000), aliasKey: Optional(302a300506032b6570032100e0c8ec2758a5879ffac226a13c0c516b799e72e35141a0dd828f94d37988a4b7), children: [], duplicates: [], ethereumHash: 14 bytes, evmAddress: Optional(0x3078303030303030303030303030303030303030), prngBytes: nil, prngNumber: Optional(4)) \ No newline at end of file diff --git a/protobufs b/protobufs index f3ebaed1..d88484a3 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit f3ebaed10173a074931650a546dd89dbc3d87cd8 +Subproject commit d88484a3b2e2100b1b9a7ed77d476baf80a58303