diff --git a/Sources/Hedera/Account/AccountBalance.swift b/Sources/Hedera/Account/AccountBalance.swift index 3e738d14..0ccb9700 100644 --- a/Sources/Hedera/Account/AccountBalance.swift +++ b/Sources/Hedera/Account/AccountBalance.swift @@ -21,7 +21,7 @@ import Foundation import HederaProtobufs -private struct TokenBalance { +private struct TokenBalance: Sendable { fileprivate let id: TokenId fileprivate let balance: UInt64 fileprivate let decimals: UInt32 @@ -67,11 +67,10 @@ public struct AccountBalance: Sendable { /// Token balances for the referenced account. /// /// This access is *`O(n)`*. - @available(*, deprecated, message: "use a mirror query") public var tokenBalances: [TokenId: UInt64] { tokenBalancesInner } // hack to work around deprecated warning - private var tokenDecimalsInner: [TokenId: UInt32] { + public var tokenDecimalsInner: [TokenId: UInt32] { Dictionary(uniqueKeysWithValues: tokensInner.map { ($0.id, $0.decimals) }) } diff --git a/Sources/Hedera/Account/AccountCreateTransaction.swift b/Sources/Hedera/Account/AccountCreateTransaction.swift index ef5535c4..d2b7a0fe 100644 --- a/Sources/Hedera/Account/AccountCreateTransaction.swift +++ b/Sources/Hedera/Account/AccountCreateTransaction.swift @@ -32,7 +32,7 @@ public final class AccountCreateTransaction: Transaction { autoRenewPeriod: Duration? = .days(90), autoRenewAccountId: AccountId? = nil, accountMemo: String = "", - maxAutomaticTokenAssociations: UInt32 = 0, + maxAutomaticTokenAssociations: Int32 = 0, alias: EvmAddress? = nil, stakedAccountId: AccountId? = nil, stakedNodeId: UInt64? = nil, @@ -59,7 +59,7 @@ public final class AccountCreateTransaction: Transaction { self.receiverSignatureRequired = data.receiverSigRequired self.autoRenewPeriod = data.hasAutoRenewPeriod ? .fromProtobuf(data.autoRenewPeriod) : nil self.accountMemo = data.memo - self.maxAutomaticTokenAssociations = UInt32(data.maxAutomaticTokenAssociations) + self.maxAutomaticTokenAssociations = data.maxAutomaticTokenAssociations if let id = data.stakedID { switch id { @@ -175,7 +175,7 @@ public final class AccountCreateTransaction: Transaction { } /// The maximum number of tokens that an Account can be implicitly associated with. - public var maxAutomaticTokenAssociations: UInt32 { + public var maxAutomaticTokenAssociations: Int32 { willSet { ensureNotFrozen() } @@ -183,7 +183,7 @@ public final class AccountCreateTransaction: Transaction { /// Sets the maximum number of tokens that an Account can be implicitly associated with. @discardableResult - public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: UInt32) -> Self { + public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: Int32) -> Self { self.maxAutomaticTokenAssociations = maxAutomaticTokenAssociations return self @@ -288,7 +288,7 @@ extension AccountCreateTransaction: ToProtobuf { autoRenewPeriod?.toProtobufInto(&proto.autoRenewPeriod) // autoRenewAccountId?.toProtobufInto(&proto.autoRenewAccount) proto.memo = accountMemo - proto.maxAutomaticTokenAssociations = Int32(maxAutomaticTokenAssociations) + proto.maxAutomaticTokenAssociations = maxAutomaticTokenAssociations if let alias = alias { proto.alias = alias.data diff --git a/Sources/Hedera/Account/AccountInfo.swift b/Sources/Hedera/Account/AccountInfo.swift index 05165e18..9c60c1b8 100644 --- a/Sources/Hedera/Account/AccountInfo.swift +++ b/Sources/Hedera/Account/AccountInfo.swift @@ -44,7 +44,7 @@ public struct AccountInfo: Sendable { autoRenewPeriod: Duration?, accountMemo: String, ownedNfts: UInt64, - maxAutomaticTokenAssociations: UInt32, + maxAutomaticTokenAssociations: Int32, aliasKey: PublicKey?, ethereumNonce: UInt64, ledgerId: LedgerId, @@ -140,7 +140,7 @@ public struct AccountInfo: Sendable { public let ownedNfts: UInt64 /// The maximum number of tokens that an Account can be implicitly associated with. - public let maxAutomaticTokenAssociations: UInt32 + public let maxAutomaticTokenAssociations: Int32 /// The public key which aliases to this account. public let aliasKey: PublicKey? @@ -193,7 +193,7 @@ extension AccountInfo: TryProtobufCodable { autoRenewPeriod: .fromProtobuf(autoRenewPeriod), accountMemo: proto.memo, ownedNfts: UInt64(proto.ownedNfts), - maxAutomaticTokenAssociations: UInt32(proto.maxAutomaticTokenAssociations), + maxAutomaticTokenAssociations: proto.maxAutomaticTokenAssociations, aliasKey: try .fromAliasBytes(proto.alias), ethereumNonce: UInt64(proto.ethereumNonce), ledgerId: .fromBytes(proto.ledgerID), @@ -217,7 +217,7 @@ extension AccountInfo: TryProtobufCodable { autoRenewPeriod?.toProtobufInto(&proto.autoRenewPeriod) proto.memo = accountMemo proto.ownedNfts = Int64(ownedNfts) - proto.maxAutomaticTokenAssociations = Int32(maxAutomaticTokenAssociations) + proto.maxAutomaticTokenAssociations = maxAutomaticTokenAssociations proto.alias = aliasKey?.toProtobufBytes() ?? Data() proto.ethereumNonce = Int64(ethereumNonce) proto.ledgerID = ledgerId.bytes diff --git a/Sources/Hedera/Account/AccountUpdateTransaction.swift b/Sources/Hedera/Account/AccountUpdateTransaction.swift index 0d8f2659..3d2295d7 100644 --- a/Sources/Hedera/Account/AccountUpdateTransaction.swift +++ b/Sources/Hedera/Account/AccountUpdateTransaction.swift @@ -73,7 +73,7 @@ public final class AccountUpdateTransaction: Transaction { self.accountMemo = data.hasMemo ? data.memo.value : nil self.maxAutomaticTokenAssociations = data.hasMaxAutomaticTokenAssociations - ? UInt32(data.maxAutomaticTokenAssociations.value) : nil + ? data.maxAutomaticTokenAssociations.value : nil self.stakedAccountId = stakedAccountId self.stakedNodeId = stakedNodeId self.declineStakingReward = data.hasDeclineReward ? data.declineReward.value : nil @@ -227,7 +227,7 @@ public final class AccountUpdateTransaction: Transaction { } /// The maximum number of tokens that an Account can be implicitly associated with. - public var maxAutomaticTokenAssociations: UInt32? { + public var maxAutomaticTokenAssociations: Int32? { willSet { ensureNotFrozen() } @@ -235,7 +235,7 @@ public final class AccountUpdateTransaction: Transaction { /// Sets the maximum number of tokens that an Account can be implicitly associated with. @discardableResult - public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: UInt32) -> Self { + public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: Int32) -> Self { self.maxAutomaticTokenAssociations = maxAutomaticTokenAssociations return self @@ -350,7 +350,7 @@ extension AccountUpdateTransaction: ToProtobuf { if let maxAutomaticTokenAssociations = maxAutomaticTokenAssociations { proto.maxAutomaticTokenAssociations = Google_Protobuf_Int32Value( - Int32(maxAutomaticTokenAssociations)) + maxAutomaticTokenAssociations) } if let stakedAccountId = stakedAccountId { diff --git a/Sources/Hedera/AnyTransaction.swift b/Sources/Hedera/AnyTransaction.swift index f14d80b8..5e9c617d 100644 --- a/Sources/Hedera/AnyTransaction.swift +++ b/Sources/Hedera/AnyTransaction.swift @@ -51,6 +51,7 @@ internal enum ServicesTransactionDataList { case tokenMint([Proto_TokenMintTransactionBody]) case tokenPause([Proto_TokenPauseTransactionBody]) case tokenRevokeKyc([Proto_TokenRevokeKycTransactionBody]) + case tokenReject([Proto_TokenRejectTransactionBody]) case tokenUnfreeze([Proto_TokenUnfreezeAccountTransactionBody]) case tokenUnpause([Proto_TokenUnpauseTransactionBody]) case tokenUpdate([Proto_TokenUpdateTransactionBody]) @@ -235,6 +236,10 @@ internal enum ServicesTransactionDataList { array.append(data) self = .tokenUpdateNfts(array) + case (.tokenReject(var array), .tokenReject(let data)): + array.append(data) + self = .tokenReject(array) + default: throw HError.fromProtobuf("mismatched transaction types") } @@ -302,6 +307,7 @@ extension ServicesTransactionDataList: TryFromProtobuf { 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 .tokenReject(let data): value = .tokenReject([data]) } for transaction in iter { diff --git a/Sources/Hedera/Contract/ContractCreateFlow.swift b/Sources/Hedera/Contract/ContractCreateFlow.swift index ad309100..9ccdb3d8 100644 --- a/Sources/Hedera/Contract/ContractCreateFlow.swift +++ b/Sources/Hedera/Contract/ContractCreateFlow.swift @@ -52,7 +52,7 @@ public final class ContractCreateFlow { constructorParameters: Data = Data(), gas: UInt64 = 0, initialBalance: Hbar = .zero, - maxAutomaticTokenAssociations: UInt32 = 0, + maxAutomaticTokenAssociations: Int32 = 0, declineStakingReward: Bool = false, adminKey: Key? = nil, autoRenewAccountId: AccountId? = nil, @@ -79,7 +79,7 @@ public final class ContractCreateFlow { fileprivate var constructorParameters: Data fileprivate var gas: UInt64 fileprivate var initialBalance: Hbar - fileprivate var maxAutomaticTokenAssociations: UInt32 + fileprivate var maxAutomaticTokenAssociations: Int32 fileprivate var declineStakingReward: Bool fileprivate var adminKey: Key? // fileprivate var proxyAccountId: AccountId? @@ -220,7 +220,7 @@ public final class ContractCreateFlow { } /// The maximum number of tokens that the contract can be automatically associated with. - public var maxAutomaticTokenAssociations: UInt32 { + public var maxAutomaticTokenAssociations: Int32 { get { contractCreateData.maxAutomaticTokenAssociations } set(value) { contractCreateData.maxAutomaticTokenAssociations = value } } @@ -229,7 +229,7 @@ public final class ContractCreateFlow { /// /// - Returns: `self` @discardableResult - public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: UInt32) -> Self { + public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: Int32) -> Self { self.maxAutomaticTokenAssociations = maxAutomaticTokenAssociations return self diff --git a/Sources/Hedera/Contract/ContractCreateTransaction.swift b/Sources/Hedera/Contract/ContractCreateTransaction.swift index e3bc54a2..92f0fbdf 100644 --- a/Sources/Hedera/Contract/ContractCreateTransaction.swift +++ b/Sources/Hedera/Contract/ContractCreateTransaction.swift @@ -56,7 +56,7 @@ public final class ContractCreateTransaction: Transaction { autoRenewPeriod: Duration? = .days(90), constructorParameters: Data? = nil, contractMemo: String = "", - maxAutomaticTokenAssociations: UInt32 = 0, + maxAutomaticTokenAssociations: Int32 = 0, autoRenewAccountId: AccountId? = nil, stakedAccountId: AccountId? = nil, stakedNodeId: UInt64? = nil, @@ -117,7 +117,7 @@ public final class ContractCreateTransaction: Transaction { self.autoRenewPeriod = .fromProtobuf(data.autoRenewPeriod) self.constructorParameters = !data.constructorParameters.isEmpty ? data.constructorParameters : nil self.contractMemo = data.memo - self.maxAutomaticTokenAssociations = UInt32(data.maxAutomaticTokenAssociations) + self.maxAutomaticTokenAssociations = data.maxAutomaticTokenAssociations self.autoRenewAccountId = data.hasAutoRenewAccountID ? try .fromProtobuf(data.autoRenewAccountID) : nil self.stakedAccountId = stakedAccountId self.stakedNodeId = stakedNodeId @@ -285,7 +285,7 @@ public final class ContractCreateTransaction: Transaction { } /// The maximum number of tokens that this contract can be automatically associated with. - public var maxAutomaticTokenAssociations: UInt32 { + public var maxAutomaticTokenAssociations: Int32 { willSet { ensureNotFrozen() } @@ -293,7 +293,7 @@ public final class ContractCreateTransaction: Transaction { /// Sets the maximum number of tokens that this contract can be automatically associated with. @discardableResult - public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: UInt32) -> Self { + public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: Int32) -> Self { self.maxAutomaticTokenAssociations = maxAutomaticTokenAssociations return self diff --git a/Sources/Hedera/Contract/ContractInfo.swift b/Sources/Hedera/Contract/ContractInfo.swift index b0393883..0370bae5 100644 --- a/Sources/Hedera/Contract/ContractInfo.swift +++ b/Sources/Hedera/Contract/ContractInfo.swift @@ -59,7 +59,7 @@ public struct ContractInfo { public let autoRenewAccountId: AccountId? /// The maximum number of tokens that a contract can be implicitly associated with. - public let maxAutomaticTokenAssociations: UInt32 + public let maxAutomaticTokenAssociations: Int32 /// Ledger ID for the network the response was returned from. public let ledgerId: LedgerId @@ -103,7 +103,7 @@ extension ContractInfo: TryProtobufCodable { balance: .fromTinybars(Int64(proto.balance)), isDeleted: proto.deleted, autoRenewAccountId: try .fromProtobuf(autoRenewAccountId), - maxAutomaticTokenAssociations: UInt32(proto.maxAutomaticTokenAssociations), + maxAutomaticTokenAssociations: proto.maxAutomaticTokenAssociations, ledgerId: .fromBytes(proto.ledgerID), stakingInfo: try .fromProtobuf(proto.stakingInfo) ) @@ -122,7 +122,7 @@ extension ContractInfo: TryProtobufCodable { proto.balance = UInt64(balance.toTinybars()) proto.deleted = isDeleted autoRenewAccountId?.toProtobufInto(&proto.autoRenewAccountID) - proto.maxAutomaticTokenAssociations = Int32(maxAutomaticTokenAssociations) + proto.maxAutomaticTokenAssociations = maxAutomaticTokenAssociations proto.ledgerID = ledgerId.bytes proto.stakingInfo = stakingInfo.toProtobuf() } diff --git a/Sources/Hedera/Contract/ContractUpdateTransaction.swift b/Sources/Hedera/Contract/ContractUpdateTransaction.swift index b27eec12..a6ab9323 100644 --- a/Sources/Hedera/Contract/ContractUpdateTransaction.swift +++ b/Sources/Hedera/Contract/ContractUpdateTransaction.swift @@ -32,7 +32,7 @@ public final class ContractUpdateTransaction: Transaction { adminKey: Key? = nil, autoRenewPeriod: Duration? = nil, contractMemo: String? = nil, - maxAutomaticTokenAssociations: UInt32? = nil, + maxAutomaticTokenAssociations: Int32? = nil, autoRenewAccountId: AccountId? = nil, proxyAccountId: AccountId? = nil, stakedAccountId: AccountId? = nil, @@ -87,7 +87,7 @@ public final class ContractUpdateTransaction: Transaction { self.autoRenewPeriod = data.hasAutoRenewPeriod ? .fromProtobuf(data.autoRenewPeriod) : nil self.contractMemo = memo self.maxAutomaticTokenAssociations = - data.hasMaxAutomaticTokenAssociations ? UInt32(data.maxAutomaticTokenAssociations.value) : nil + data.hasMaxAutomaticTokenAssociations ? data.maxAutomaticTokenAssociations.value : nil self.autoRenewAccountId = data.hasAutoRenewAccountID ? try .fromProtobuf(data.autoRenewAccountID) : nil self.proxyAccountId = data.hasProxyAccountID ? try .fromProtobuf(data.proxyAccountID) : nil self.stakedAccountId = stakedAccountId @@ -180,7 +180,7 @@ public final class ContractUpdateTransaction: Transaction { } /// The maximum number of tokens that this contract can be automatically associated with. - public var maxAutomaticTokenAssociations: UInt32? { + public var maxAutomaticTokenAssociations: Int32? { willSet { ensureNotFrozen() } @@ -188,7 +188,7 @@ public final class ContractUpdateTransaction: Transaction { /// Sets the maximum number of tokens that this contract can be automatically associated with. @discardableResult - public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: UInt32?) -> Self { + public func maxAutomaticTokenAssociations(_ maxAutomaticTokenAssociations: Int32?) -> Self { self.maxAutomaticTokenAssociations = maxAutomaticTokenAssociations return self diff --git a/Sources/Hedera/FeeSchedule/RequestType.swift b/Sources/Hedera/FeeSchedule/RequestType.swift index 57cbf914..d6373c97 100644 --- a/Sources/Hedera/FeeSchedule/RequestType.swift +++ b/Sources/Hedera/FeeSchedule/RequestType.swift @@ -256,8 +256,8 @@ public enum RequestType { /// Delete a node case nodeDelete - /// Get the info for a node - case nodeGetInfo + /// Reject a Token + case tokenReject // this literally can't be smaller. // swiftlint:disable:next function_body_length @@ -341,7 +341,7 @@ public enum RequestType { case .nodeCreate: self = .nodeCreate case .nodeDelete: self = .nodeDelete case .nodeUpdate: self = .nodeUpdate - case .nodeGetInfo: self = .nodeGetInfo + case .tokenReject: self = .tokenReject case .UNRECOGNIZED(let code): throw HError.fromProtobuf("unrecognized RequestType: `\(code)`") @@ -427,7 +427,7 @@ public enum RequestType { case .nodeCreate: return .nodeCreate case .nodeUpdate: return .nodeUpdate case .nodeDelete: return .nodeDelete - case .nodeGetInfo: return .nodeGetInfo + case .tokenReject: return .tokenReject } } } diff --git a/Sources/Hedera/Schedule/ScheduleInfo.swift b/Sources/Hedera/Schedule/ScheduleInfo.swift index ba995c2a..5278ceb8 100644 --- a/Sources/Hedera/Schedule/ScheduleInfo.swift +++ b/Sources/Hedera/Schedule/ScheduleInfo.swift @@ -115,6 +115,7 @@ public struct ScheduleInfo: Sendable { case .nodeCreate(let data): proto.data = .nodeCreate(data) 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 nil: break } diff --git a/Sources/Hedera/Status.swift b/Sources/Hedera/Status.swift index 45f5514d..4a3a3b18 100644 --- a/Sources/Hedera/Status.swift +++ b/Sources/Hedera/Status.swift @@ -946,6 +946,87 @@ public enum Status: Equatable { /// NFT serial numbers are missing in the TokenUpdateNftsTransactionBody case missingSerialNumbers // = 336 + /// Admin key is not set on token + + case tokenHasNoAdminKey // = 337 + + /// A transaction failed because the consensus node identified is + /// deleted from the address book. + case nodeDeleted // = 338 + + /// A transaction failed because the consensus node identified is not valid or + /// does not exist in state. + case invalidNodeID // = 339 + + /// A transaction failed because one or more entries in the list of + /// service endpoints for the `gossip_endpoint` field is invalid.
+ /// The most common cause for this response is a service endpoint that has + /// the domain name (DNS) set rather than address and port. + case invalidGossipEndpoint // = 340 + + /// A transaction failed because the node account identifier provided + /// does not exist or is not valid.
+ /// One common source of this error is providing a node account identifier + /// using the "alias" form rather than "numeric" form. + case invalidNodeAccountID // = 341 + + /// A transaction failed because the description field cannot be encoded + /// as UTF-8 or is more than 100 bytes when encoded. + case invalidNodeDescription // = 342 + + /// A transaction failed because one or more entries in the list of + /// service endpoints for the `service_endpoint` field is invalid. + case invalidServiceEndpoint // = 343 + + /// A transaction failed because the TLS certificate provided for the + /// node is missing or invalid. + case invalidGossipCaCertificate // = 344 + + /// A transaction failed because the hash provided for the gRPC certificate + /// is present but invalid. + case invalidGrpcCertificate // = 345 + + /// The maximum automatic associations value is not valid. + case invalidMaxAutoAssociations // = 346 + + /// The maximum number of nodes allowed in the address book have been created. + case maxNodesCreated // = 347 + + /// In ServiceEndpoint, domain_name and ipAddressV4 are mutually exclusive + case ipFqdnCannotBeSetForSameEndpoint // = 348 + + /// Fully qualified domain name is not allowed in gossip_endpoint + case gossipEndpointCannotHaveFqdn // = 349 + + /// In ServiceEndpoint, domain_name size too large + case fqdnSizeTooLarge // = 350 + + /// ServiceEndpoint is invalid + case invalidEndpoint // = 351 + + /// The number of gossip endpoints exceeds the limit + case gossipEndpointsExceededLimit // = 352 + + /// The transaction attempted to use duplicate `TokenReference` + case tokenReferenceRepeated // = 353 + + /// The account id specified as the owner in `TokenReject` is invalid or does not exist. + case invalidOwnerID // = 354 + + /// The transaction attempted to use more than the allowed number of `TokenReference`. + case tokenReferenceListSizeLimitExceeded // = 355 + + /// The number of service endpoints exceeds the limit + case serviceEndpointsExceededLimit // = 356 + + /// The IPv4 address is invalid + case invalidIpv4Address // = 357 + + /// The transaction attempted to use empty `TokenReference` list. + case emptyTokenReferenceList // = 358 + + /// The node account is not allowed to be updated + case updateNodeAccountNotAllowed // = 359 /// swift-format-ignore: AlwaysUseLowerCamelCase case unrecognized(Int32) @@ -1249,6 +1330,29 @@ public enum Status: Equatable { case 334: self = .tokenHasNoMetadataKey case 335: self = .missingTokenMetadata case 336: self = .missingSerialNumbers + case 337: self = .tokenHasNoAdminKey + case 338: self = .nodeDeleted + case 339: self = .invalidNodeID + case 340: self = .invalidGossipEndpoint + case 341: self = .invalidNodeAccountID + case 342: self = .invalidNodeDescription + case 343: self = .invalidServiceEndpoint + case 344: self = .invalidGossipCaCertificate + case 345: self = .invalidGrpcCertificate + case 346: self = .invalidMaxAutoAssociations + case 347: self = .maxNodesCreated + case 348: self = .ipFqdnCannotBeSetForSameEndpoint + case 349: self = .gossipEndpointCannotHaveFqdn + case 350: self = .fqdnSizeTooLarge + case 351: self = .invalidEndpoint + case 352: self = .gossipEndpointsExceededLimit + case 353: self = .tokenReferenceRepeated + case 354: self = .invalidOwnerID + case 355: self = .tokenReferenceListSizeLimitExceeded + case 356: self = .serviceEndpointsExceededLimit + case 357: self = .invalidIpv4Address + case 358: self = .emptyTokenReferenceList + case 359: self = .updateNodeAccountNotAllowed default: self = .unrecognized(rawValue) } } @@ -1550,6 +1654,29 @@ public enum Status: Equatable { case .tokenHasNoMetadataKey: return 334 case .missingTokenMetadata: return 335 case .missingSerialNumbers: return 336 + case .tokenHasNoAdminKey: return 337 + case .nodeDeleted: return 338 + case .invalidNodeID: return 339 + case .invalidGossipEndpoint: return 340 + case .invalidNodeAccountID: return 341 + case .invalidNodeDescription: return 342 + case .invalidServiceEndpoint: return 343 + case .invalidGossipCaCertificate: return 344 + case .invalidGrpcCertificate: return 345 + case .invalidMaxAutoAssociations: return 346 + case .maxNodesCreated: return 347 + case .ipFqdnCannotBeSetForSameEndpoint: return 348 + case .gossipEndpointCannotHaveFqdn: return 349 + case .fqdnSizeTooLarge: return 350 + case .invalidEndpoint: return 351 + case .gossipEndpointsExceededLimit: return 352 + case .tokenReferenceRepeated: return 353 + case .invalidOwnerID: return 354 + case .tokenReferenceListSizeLimitExceeded: return 355 + case .serviceEndpointsExceededLimit: return 356 + case .invalidIpv4Address: return 357 + case .emptyTokenReferenceList: return 358 + case .updateNodeAccountNotAllowed: return 359 case .unrecognized(let i): return i } } @@ -1854,6 +1981,29 @@ extension Status: CaseIterable { .tokenHasNoMetadataKey, .missingTokenMetadata, .missingSerialNumbers, + .tokenHasNoAdminKey, + .nodeDeleted, + .invalidNodeID, + .invalidGossipEndpoint, + .invalidNodeAccountID, + .invalidNodeDescription, + .invalidServiceEndpoint, + .invalidGossipCaCertificate, + .invalidGrpcCertificate, + .invalidMaxAutoAssociations, + .maxNodesCreated, + .ipFqdnCannotBeSetForSameEndpoint, + .gossipEndpointCannotHaveFqdn, + .fqdnSizeTooLarge, + .invalidEndpoint, + .gossipEndpointsExceededLimit, + .tokenReferenceRepeated, + .invalidOwnerID, + .tokenReferenceListSizeLimitExceeded, + .serviceEndpointsExceededLimit, + .invalidIpv4Address, + .emptyTokenReferenceList, + .updateNodeAccountNotAllowed, ] } @@ -2156,6 +2306,29 @@ extension Status { 334: "TOKEN_HAS_NO_METADATA_KEY", 335: "MISSING_TOKEN_METADATA", 336: "MISSING_SERIAL_NUMBERS", + 337: "TOKEN_HAS_NO_ADMIN_KEY", + 338: "NODE_DELETED", + 339: "INVALID_NODE_ID", + 340: "INVALID_GOSSIP_ENDPOINT", + 341: "INVALID_NODE_ACCOUNT_ID", + 342: "INVALID_NODE_DESCRIPTION", + 343: "INVALID_SERVICE_ENDPOINT", + 344: "INVALID_GOSSIP_CA_CERTIFICATE", + 345: "INVALID_GRPC_CERTIFICATE", + 346: "INVALID_MAX_AUTO_ASSOCIATIONS", + 347: "MAX_NODES_CREATED", + 348: "IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT", + 349: "GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN", + 350: "FQDN_SIZE_TOO_LARGE", + 351: "INVALID_ENDPOINT", + 352: "GOSSIP_ENDPOINTS_EXCEEDED_LIMIT", + 353: "TOKEN_REFERENCE_REPEATED", + 354: "INVALID_OWNER_ID", + 355: "TOKEN_REFERENCE_LIST_SIZE_LIMIT_EXCEEDED", + 356: "SERVICE_ENDPOINTS_EXCEEDED_LIMIT", + 357: "INVALID_IPV4_ADDRESS", + 358: "EMPTY_TOKEN_REFERENCE_LIST", + 359: "UPDATE_NODE_ACCOUNT_NOT_ALLOWED", ] } diff --git a/Sources/Hedera/Token/TokenRejectTransaction.swift b/Sources/Hedera/Token/TokenRejectTransaction.swift new file mode 100644 index 00000000..641e31b0 --- /dev/null +++ b/Sources/Hedera/Token/TokenRejectTransaction.swift @@ -0,0 +1,155 @@ +/* + * ‌ + * 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 GRPC +import HederaProtobufs + +/// Reject undesired Tokens or NFTs. +public final class TokenRejectTransaction: Transaction { + /// Create a new `TokenRejectTransaction`. + public init( + owner: AccountId? = nil, + tokenIds: [TokenId] = [], + nftIds: [NftId] = [] + ) { + self.owner = owner + self.tokenIds = tokenIds + self.nftIds = nftIds + + super.init() + } + + internal init(protobuf proto: Proto_TransactionBody, _ data: Proto_TokenRejectTransactionBody) throws { + self.owner = data.hasOwner ? try .fromProtobuf(data.owner) : nil + self.tokenIds = [] + self.nftIds = [] + + for reference in data.rejections { + switch reference.tokenIdentifier { + case .fungibleToken(let tokenId): + self.tokenIds.append(TokenId(protobuf: tokenId)) + case .nft(let nftId): + self.nftIds.append(NftId(protobuf: nftId)) + default: + throw HError.fromProtobuf("invalid token identifier") + } + } + + try super.init(protobuf: proto) + } + + /// The account holding the token to be rejected. + public var owner: AccountId? { + willSet { + ensureNotFrozen() + } + } + + /// Sets account holding the token to be rejected. + @discardableResult + public func owner(_ owner: AccountId) -> Self { + self.owner = owner + + return self + } + + public var tokenIds: [TokenId] { + willSet { + ensureNotFrozen() + } + } + + @discardableResult + public func tokenIds(_ tokenIds: [TokenId]) -> Self { + self.tokenIds = tokenIds + + return self + } + + /// Append a fungible token to the list of tokens to be rejected. + @discardableResult + public func addTokenId(_ tokenId: TokenId) -> Self { + self.tokenIds.append(tokenId) + + return self + } + + public var nftIds: [NftId] { + willSet { + ensureNotFrozen() + } + } + + @discardableResult + public func nftIds(_ nftIds: [NftId]) -> Self { + self.nftIds = nftIds + + return self + } + + /// Append an NFT to the list of tokens to be rejected. + @discardableResult + public func addNftId(_ nftId: NftId) -> Self { + self.nftIds.append(nftId) + + return self + } + + internal override func validateChecksums(on ledgerId: LedgerId) throws { + try owner?.validateChecksums(on: ledgerId) + try super.validateChecksums(on: ledgerId) + } + + internal override func transactionExecute(_ channel: GRPCChannel, _ request: Proto_Transaction) async throws + -> Proto_TransactionResponse + { + try await Proto_TokenServiceAsyncClient(channel: channel).deleteToken(request) + } + + internal override func toTransactionDataProtobuf(_ chunkInfo: ChunkInfo) -> Proto_TransactionBody.OneOf_Data { + _ = chunkInfo.assertSingleTransaction() + + return .tokenReject(toProtobuf()) + } +} + +extension TokenRejectTransaction: ToProtobuf { + internal typealias Protobuf = Proto_TokenRejectTransactionBody + + internal func toProtobuf() -> Protobuf { + .with { [self] proto in + owner?.toProtobufInto(&proto.owner) + + for tokenId in self.tokenIds { + proto.rejections.append(.with { $0.fungibleToken = tokenId.toProtobuf() }) + } + + for nftId in self.nftIds { + proto.rejections.append(.with { $0.nft = nftId.toProtobuf() }) + } + } + } +} + +extension TokenRejectTransaction { + internal func toSchedulableTransactionData() -> Proto_SchedulableTransactionBody.OneOf_Data { + .tokenReject(toProtobuf()) + } +} diff --git a/Sources/Hedera/Transaction/Transaction+FromProtobuf.swift b/Sources/Hedera/Transaction/Transaction+FromProtobuf.swift index 10e99e23..1eaee783 100644 --- a/Sources/Hedera/Transaction/Transaction+FromProtobuf.swift +++ b/Sources/Hedera/Transaction/Transaction+FromProtobuf.swift @@ -201,6 +201,10 @@ extension Transaction { case .tokenUpdateNfts(let value): let value = try intoOnlyValue(value) return try TokenUpdateNftsTransaction(protobuf: firstBody, value) + + case .tokenReject(let value): + let value = try intoOnlyValue(value) + return try TokenRejectTransaction(protobuf: firstBody, value) } } } diff --git a/Sources/HederaProtobufs/Services/basic_types.pb.swift b/Sources/HederaProtobufs/Services/basic_types.pb.swift index ae694152..8bd42b87 100644 --- a/Sources/HederaProtobufs/Services/basic_types.pb.swift +++ b/Sources/HederaProtobufs/Services/basic_types.pb.swift @@ -742,8 +742,8 @@ public enum Proto_HederaFunctionality: SwiftProtobuf.Enum { case nodeDelete // = 91 ///* - /// Get Node information - case nodeGetInfo // = 92 + /// Transfer one or more token balances held by the requesting account to the treasury for each token type. + case tokenReject // = 92 case UNRECOGNIZED(Int) public init() { @@ -830,7 +830,7 @@ public enum Proto_HederaFunctionality: SwiftProtobuf.Enum { case 89: self = .nodeCreate case 90: self = .nodeUpdate case 91: self = .nodeDelete - case 92: self = .nodeGetInfo + case 92: self = .tokenReject default: self = .UNRECOGNIZED(rawValue) } } @@ -915,7 +915,7 @@ public enum Proto_HederaFunctionality: SwiftProtobuf.Enum { case .nodeCreate: return 89 case .nodeUpdate: return 90 case .nodeDelete: return 91 - case .nodeGetInfo: return 92 + case .tokenReject: return 92 case .UNRECOGNIZED(let i): return i } } @@ -1005,7 +1005,7 @@ extension Proto_HederaFunctionality: CaseIterable { .nodeCreate, .nodeUpdate, .nodeDelete, - .nodeGetInfo, + .tokenReject, ] } @@ -2439,26 +2439,35 @@ public struct Proto_CurrentAndNextFeeSchedule { } ///* -/// Contains the IP address and the port representing a service endpoint of a Node in a network. Used -/// to reach the Hedera API and submit transactions to the network. +/// Contains the IP address and the port representing a service endpoint of +/// a Node in a network. Used to reach the Hedera API and submit transactions +/// to the network. +/// +/// When the `domain_name` field is set, the `ipAddressV4` field +/// MUST NOT be set.
+/// When the `ipAddressV4` field is set, the `domain_name` field +/// MUST NOT be set. public struct Proto_ServiceEndpoint { // 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 32-bit IPv4 address of the node encoded in left to right order (e.g. 127.0.0.1 has 127 - /// as its first byte) + /// The 4-byte IPv4 address of the endpoint encoded in left to right order + /// (e.g. 127.0.0.1 has bytes [127, 0, 0, 1]) public var ipAddressV4: Data = Data() ///* - /// The port of the node + /// The port of the service endpoint public var port: Int32 = 0 ///* - /// A node domain name - /// This MUST be the fully qualified domain name of the node. + /// A node domain name.
+ /// This MUST be the fully qualified domain(DNS) name of the node.
/// This value MUST NOT be more than 253 characters. + /// domain_name and ipAddressV4 are mutually exclusive. + /// When the `domain_name` field is set, the `ipAddressV4` field MUST NOT be set.
+ /// When the `ipAddressV4` field is set, the `domain_name` field MUST NOT be set. public var domainName: String = String() public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -2470,8 +2479,8 @@ public struct Proto_ServiceEndpoint { /// The data about a node, including its service endpoints and the Hedera account to be paid for /// services provided by the node (that is, queries answered and transactions submitted.) /// -/// If the serviceEndpoint list is not set, or empty, then the endpoint given by the -/// (deprecated) ipAddress and portno fields should be used. +/// If the `serviceEndpoint` list is not set, or empty, then the endpoint given by the +/// (deprecated) `ipAddress` and `portno` fields should be used. /// /// All fields are populated in the 0.0.102 address book file while only fields that start with # are /// populated in the 0.0.101 address book file. @@ -3071,7 +3080,7 @@ extension Proto_HederaFunctionality: SwiftProtobuf._ProtoNameProviding { 89: .same(proto: "NodeCreate"), 90: .same(proto: "NodeUpdate"), 91: .same(proto: "NodeDelete"), - 92: .same(proto: "NodeGetInfo"), + 92: .same(proto: "TokenReject"), ] } diff --git a/Sources/HederaProtobufs/Services/contract_create.pb.swift b/Sources/HederaProtobufs/Services/contract_create.pb.swift index 341d8b12..3f6ed9c4 100644 --- a/Sources/HederaProtobufs/Services/contract_create.pb.swift +++ b/Sources/HederaProtobufs/Services/contract_create.pb.swift @@ -215,8 +215,12 @@ public struct Proto_ContractCreateTransactionBody { } ///* - /// The maximum number of tokens that this contract can be automatically associated - /// with (i.e., receive air-drops from). + /// The maximum number of tokens that can be auto-associated with the contract.
+ /// If this is less than or equal to `used_auto_associations`, or 0, then this contract + /// MUST manually associate with a token before transacting in that token.
+ /// This value MAY also be `-1` to indicate no limit.
+ /// This value MUST NOT be less than `-1`.
+ /// By default this value is 0 for contracts. public var maxAutomaticTokenAssociations: Int32 { get {return _storage._maxAutomaticTokenAssociations} set {_uniqueStorage()._maxAutomaticTokenAssociations = newValue} diff --git a/Sources/HederaProtobufs/Services/contract_update.pb.swift b/Sources/HederaProtobufs/Services/contract_update.pb.swift index c38c34b2..18688d29 100644 --- a/Sources/HederaProtobufs/Services/contract_update.pb.swift +++ b/Sources/HederaProtobufs/Services/contract_update.pb.swift @@ -139,8 +139,12 @@ public struct Proto_ContractUpdateTransactionBody { } ///* - /// If set, the new maximum number of tokens that this contract can be - /// automatically associated with (i.e., receive air-drops from). + /// If set, modify the maximum number of tokens that can be auto-associated with the + /// contract.
+ /// If this is set and less than or equal to `used_auto_associations`, or 0, then this contract + /// MUST manually associate with a token before transacting in that token.
+ /// This value MAY also be `-1` to indicate no limit.
+ /// This value MUST NOT be less than `-1`. public var maxAutomaticTokenAssociations: SwiftProtobuf.Google_Protobuf_Int32Value { get {return _storage._maxAutomaticTokenAssociations ?? SwiftProtobuf.Google_Protobuf_Int32Value()} set {_uniqueStorage()._maxAutomaticTokenAssociations = newValue} diff --git a/Sources/HederaProtobufs/Services/crypto_create.pb.swift b/Sources/HederaProtobufs/Services/crypto_create.pb.swift index a4f00b8f..416fe152 100644 --- a/Sources/HederaProtobufs/Services/crypto_create.pb.swift +++ b/Sources/HederaProtobufs/Services/crypto_create.pb.swift @@ -168,8 +168,12 @@ public struct Proto_CryptoCreateTransactionBody { } ///* - /// The maximum number of tokens that an Account can be implicitly associated with. Defaults to 0 - /// and up to a maximum value of 1000. + /// The maximum number of tokens that can be auto-associated with the account.
+ /// If this is less than or equal to `used_auto_associations`, or 0, then this account + /// MUST manually associate with a token before transacting in that token.
+ /// This value MAY also be `-1` to indicate no limit.
+ /// This value MUST NOT be less than `-1`.
+ /// By default this value is 0 for accounts except for auto-created accounts which default -1. public var maxAutomaticTokenAssociations: Int32 { get {return _storage._maxAutomaticTokenAssociations} set {_uniqueStorage()._maxAutomaticTokenAssociations = newValue} diff --git a/Sources/HederaProtobufs/Services/crypto_update.pb.swift b/Sources/HederaProtobufs/Services/crypto_update.pb.swift index 11f663ac..65db6742 100644 --- a/Sources/HederaProtobufs/Services/crypto_update.pb.swift +++ b/Sources/HederaProtobufs/Services/crypto_update.pb.swift @@ -196,8 +196,12 @@ public struct Proto_CryptoUpdateTransactionBody { public mutating func clearMemo() {_uniqueStorage()._memo = nil} ///* - /// The maximum number of tokens that an Account can be implicitly associated with. Up to a 1000 - /// including implicit and explicit associations. + /// If set, modify the maximum number of tokens that can be auto-associated with the + /// account.
+ /// If this is set and less than or equal to `used_auto_associations`, or 0, then this account + /// MUST manually associate with a token before transacting in that token.
+ /// This value MAY also be `-1` to indicate no limit.
+ /// This value MUST NOT be less than `-1`. public var maxAutomaticTokenAssociations: SwiftProtobuf.Google_Protobuf_Int32Value { get {return _storage._maxAutomaticTokenAssociations ?? SwiftProtobuf.Google_Protobuf_Int32Value()} set {_uniqueStorage()._maxAutomaticTokenAssociations = newValue} diff --git a/Sources/HederaProtobufs/Services/node_create.pb.swift b/Sources/HederaProtobufs/Services/node_create.pb.swift index 3e764d1f..cd508df5 100644 --- a/Sources/HederaProtobufs/Services/node_create.pb.swift +++ b/Sources/HederaProtobufs/Services/node_create.pb.swift @@ -21,28 +21,42 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP } ///* -/// A transaction body to add a new node to the network. -/// After the node is created, the node_id for it is in the receipt. +/// 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. -/// The transaction, once complete, enables a new consensus node +/// 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.
-/// The newly created node information will be used to generate config.txt and -/// a-pulbic-NodeAlias.pem file per each node during phase 2,
-/// not active until next freeze upgrade. -public struct Proto_NodeCreateTransactionBody { +/// - 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`. +/// +/// ### Record Stream Effects +/// Upon completion the newly assigned `node_id` SHALL be in the transaction +/// receipt. +public struct Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody { // 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. ///* - /// Node account id, mandatory field, ALIAS is not allowed, only ACCOUNT_NUM. - /// If account_id does not exist, it will reject the transaction. - /// Multiple nodes can have the same account_id. + /// A Node account identifier. + ///

+ /// This account identifier MUST be in the "account number" form.
+ /// This account identifier MUST NOT use the alias field.
+ /// If the identified account does not exist, this transaction SHALL fail.
+ /// Multiple nodes MAY share the same node account.
+ /// This field is REQUIRED. public var accountID: Proto_AccountID { get {return _accountID ?? Proto_AccountID()} set {_accountID = newValue} @@ -53,52 +67,100 @@ public struct Proto_NodeCreateTransactionBody { public mutating func clearAccountID() {self._accountID = nil} ///* - /// Description of the node with UTF-8 encoding up to 100 bytes, optional field. + /// A short description of the node. + ///

+ /// This value, if set, MUST NOT exceed 100 bytes when encoded as UTF-8.
+ /// This field is OPTIONAL. public var description_p: String = String() ///* - /// Ip address and port, mandatory field. Fully qualified domain name is - /// not allowed here. Maximum number of these endpoints is 10. - /// The first in the list is used as the Internal IP address in config.txt, - /// the second in the list is used as the External IP address in config.txt, - /// the rest of IP addresses are ignored for DAB phase 2. + /// A list of service endpoints for gossip. + ///

+ /// These endpoints SHALL represent the published endpoints to which other + /// consensus nodes may _gossip_ transactions.
+ /// These endpoints MUST specify a port.
+ /// This list MUST NOT be empty.
+ /// This list MUST NOT contain more than `10` entries.
+ /// The first two entries in this list SHALL be the endpoints published to + /// all consensus nodes.
+ /// All other entries SHALL be reserved for future use. + ///

+ /// Each network may have additional requirements for these endpoints. + /// A client MUST check network-specific documentation for those + /// details.
+ /// If the network configuration value `gossipFqdnRestricted` is set, then + /// all endpoints in this list MUST supply only IP address.
+ /// If the network configuration value `gossipFqdnRestricted` is _not_ set, + /// then endpoints in this list MAY supply either IP address or FQDN, but + /// MUST NOT supply both values for the same endpoint. public var gossipEndpoint: [Proto_ServiceEndpoint] = [] ///* - /// A node's grpc service IP addresses and ports, IP:Port is mandatory, - /// fully qualified domain name is optional. Maximum number of these endpoints is 8. + /// A list of service endpoints for gRPC calls. + ///

+ /// These endpoints SHALL represent the published gRPC endpoints to which + /// clients may submit transactions.
+ /// These endpoints MUST specify a port.
+ /// Endpoints in this list MAY supply either IP address or FQDN, but MUST + /// NOT supply both values for the same endpoint.
+ /// This list MUST NOT be empty.
+ /// This list MUST NOT contain more than `8` entries. public var serviceEndpoint: [Proto_ServiceEndpoint] = [] ///* - /// The node's X509 certificate used to sign stream files (e.g., record stream - /// files). Precisely, this field is the DER encoding of gossip X509 certificate. - /// This is a mandatory field. + /// A certificate used to sign gossip events. + ///

+ /// This value MUST be a certificate of a type permitted for gossip + /// signatures.
+ /// This value MUST be the DER encoding of the certificate presented.
+ /// This field is REQUIRED and MUST NOT be empty. public var gossipCaCertificate: Data = Data() ///* - /// Hash of the node's TLS certificate. Precisely, this field is a string of - /// hexadecimal characters which translated to binary, are the SHA-384 hash of - /// the UTF-8 NFKD encoding of the node's TLS cert in PEM format. - /// Its value can be used to verify the node's certificate it presents - /// during TLS negotiations.node x509 certificate hash, optional field. + /// A hash of the node gRPC TLS certificate. + ///

+ /// This value MAY be used to verify the certificate presented by the node + /// during TLS negotiation for gRPC.
+ /// This value MUST be a SHA-384 hash.
+ /// The TLS certificate to be hashed MUST first be in PEM format and MUST be + /// encoded with UTF-8 NFKD encoding to a stream of bytes provided to + /// the hash algorithm.
+ /// This field is OPTIONAL. public var grpcCertificateHash: Data = Data() + ///* + /// An administrative key controlled by the node operator. + ///

+ /// This key MUST sign this transaction.
+ /// This key MUST sign each transaction to update this node.
+ /// This field MUST contain a valid `Key` value.
+ /// This field is REQUIRED and MUST NOT be set to an empty `KeyList`. + public var adminKey: Proto_Key { + get {return _adminKey ?? Proto_Key()} + set {_adminKey = newValue} + } + /// Returns true if `adminKey` has been explicitly set. + public var hasAdminKey: Bool {return self._adminKey != nil} + /// Clears the value of `adminKey`. Subsequent reads from it will return its default value. + public mutating func clearAdminKey() {self._adminKey = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} fileprivate var _accountID: Proto_AccountID? = nil + fileprivate var _adminKey: Proto_Key? = nil } #if swift(>=5.5) && canImport(_Concurrency) -extension Proto_NodeCreateTransactionBody: @unchecked Sendable {} +extension Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. -fileprivate let _protobuf_package = "proto" +fileprivate let _protobuf_package = "com.hedera.hapi.node.addressbook" -extension Proto_NodeCreateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".NodeCreateTransactionBody" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "account_id"), @@ -107,6 +169,7 @@ extension Proto_NodeCreateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf. 4: .standard(proto: "service_endpoint"), 5: .standard(proto: "gossip_ca_certificate"), 6: .standard(proto: "grpc_certificate_hash"), + 7: .standard(proto: "admin_key"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -121,6 +184,7 @@ extension Proto_NodeCreateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf. case 4: try { try decoder.decodeRepeatedMessageField(value: &self.serviceEndpoint) }() case 5: try { try decoder.decodeSingularBytesField(value: &self.gossipCaCertificate) }() case 6: try { try decoder.decodeSingularBytesField(value: &self.grpcCertificateHash) }() + case 7: try { try decoder.decodeSingularMessageField(value: &self._adminKey) }() default: break } } @@ -149,16 +213,20 @@ extension Proto_NodeCreateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf. if !self.grpcCertificateHash.isEmpty { try visitor.visitSingularBytesField(value: self.grpcCertificateHash, fieldNumber: 6) } + try { if let v = self._adminKey { + try visitor.visitSingularMessageField(value: v, fieldNumber: 7) + } }() try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Proto_NodeCreateTransactionBody, rhs: Proto_NodeCreateTransactionBody) -> Bool { + public static func ==(lhs: Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody, rhs: Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody) -> Bool { if lhs._accountID != rhs._accountID {return false} if lhs.description_p != rhs.description_p {return false} if lhs.gossipEndpoint != rhs.gossipEndpoint {return false} if lhs.serviceEndpoint != rhs.serviceEndpoint {return false} if lhs.gossipCaCertificate != rhs.gossipCaCertificate {return false} if lhs.grpcCertificateHash != rhs.grpcCertificateHash {return false} + if lhs._adminKey != rhs._adminKey {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/HederaProtobufs/Services/node_delete.pb.swift b/Sources/HederaProtobufs/Services/node_delete.pb.swift index 0c70245b..6c8aece3 100644 --- a/Sources/HederaProtobufs/Services/node_delete.pb.swift +++ b/Sources/HederaProtobufs/Services/node_delete.pb.swift @@ -21,21 +21,33 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP } ///* -/// Delete the given node. After deletion, it will be marked as deleted. -/// But information about it will continue to exist for a year. -/// For phase 2, this marks the node to be deleted in the merkle tree and will be used to write config.txt and -/// a-pulbic-NodeAlias.pem file per each node during prepare freeze. -/// The deleted node will not be deleted until the network is upgraded. -/// Such a deleted node can never be reused. -/// The council has to sign this transaction. This is a privileged transaction. -public struct Proto_NodeDeleteTransactionBody { +/// 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. +/// +/// ### Record Stream Effects +/// Upon completion the "deleted" `node_id` SHALL be in the transaction +/// receipt. +public struct Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody { // 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 unique id of the node to be deleted. If invalid node is specified, transaction will - /// result in INVALID_NODE_ID. + /// A consensus node identifier in the network state. + ///

+ /// The node identified MUST exist in the network address book.
+ /// The node identified MUST NOT be deleted.
+ /// This value is REQUIRED. public var nodeID: UInt64 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -44,14 +56,14 @@ public struct Proto_NodeDeleteTransactionBody { } #if swift(>=5.5) && canImport(_Concurrency) -extension Proto_NodeDeleteTransactionBody: @unchecked Sendable {} +extension Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. -fileprivate let _protobuf_package = "proto" +fileprivate let _protobuf_package = "com.hedera.hapi.node.addressbook" -extension Proto_NodeDeleteTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".NodeDeleteTransactionBody" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "node_id"), @@ -76,7 +88,7 @@ extension Proto_NodeDeleteTransactionBody: SwiftProtobuf.Message, SwiftProtobuf. try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Proto_NodeDeleteTransactionBody, rhs: Proto_NodeDeleteTransactionBody) -> Bool { + public static func ==(lhs: Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody, rhs: Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody) -> Bool { if lhs.nodeID != rhs.nodeID {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true diff --git a/Sources/HederaProtobufs/Services/node_update.pb.swift b/Sources/HederaProtobufs/Services/node_update.pb.swift index 93c6af04..6924cbfb 100644 --- a/Sources/HederaProtobufs/Services/node_update.pb.swift +++ b/Sources/HederaProtobufs/Services/node_update.pb.swift @@ -21,23 +21,43 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP } ///* -/// Modify the attribute of a node. If a field is not set in the transaction body, the -/// corresponding node attribute will be unchanged. -/// For phase 2, this marks node to be updated in the merkle tree and will be used to write config.txt and -/// a-pulbic-NodeAlias.pem file per each node during prepare freeze. -/// The node will not be updated until the network is upgraded. -/// Original node account ID has to sign the transaction. -public struct Proto_NodeUpdateTransactionBody { +/// 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`. +/// +/// ### Record Stream Effects +/// Upon completion the `node_id` for the updated entry SHALL be in the +/// transaction receipt. +public struct Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody { // 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 unique id of the Node to be updated. This must refer to an existing, non-deleted node. + /// A consensus node identifier in the network state. + ///

+ /// The node identified MUST exist in the network address book.
+ /// The node identified MUST NOT be deleted.
+ /// This value is REQUIRED. public var nodeID: UInt64 = 0 ///* - /// If set, the new node account_id. + /// An account identifier. + ///

+ /// If set, this SHALL replace the node account identifier.
+ /// If set, this transaction MUST be signed by the active `key` for _both_ + /// the current node account _and_ the identified new node account. public var accountID: Proto_AccountID { get {return _accountID ?? Proto_AccountID()} set {_accountID = newValue} @@ -48,7 +68,10 @@ public struct Proto_NodeUpdateTransactionBody { public mutating func clearAccountID() {self._accountID = nil} ///* - /// If set, the new description to be associated with the node. + /// A short description of the node. + ///

+ /// This value, if set, MUST NOT exceed 100 bytes when encoded as UTF-8.
+ /// If set, this value SHALL replace the previous value. public var description_p: SwiftProtobuf.Google_Protobuf_StringValue { get {return _description_p ?? SwiftProtobuf.Google_Protobuf_StringValue()} set {_description_p = newValue} @@ -59,15 +82,64 @@ public struct Proto_NodeUpdateTransactionBody { public mutating func clearDescription_p() {self._description_p = nil} ///* - /// If set, the new ip address and port. + /// A list of service endpoints for gossip. + ///

+ /// If set, this list MUST meet the following requirements. + ///


+ /// These endpoints SHALL represent the published endpoints to which other + /// consensus nodes may _gossip_ transactions.
+ /// These endpoints SHOULD NOT specify both address and DNS name.
+ /// This list MUST NOT be empty.
+ /// This list MUST NOT contain more than `10` entries.
+ /// The first two entries in this list SHALL be the endpoints published to + /// all consensus nodes.
+ /// All other entries SHALL be reserved for future use. + ///

+ /// Each network may have additional requirements for these endpoints. + /// A client MUST check network-specific documentation for those + /// details.
+ ///

Example
+ /// Hedera Mainnet _requires_ that address be specified, and does not + /// permit DNS name (FQDN) to be specified.
+ /// Mainnet also requires that the first entry be an "internal" IP + /// address and the second entry be an "external" IP address. + ///
+ ///
+ /// Solo, however, _requires_ DNS name (FQDN) but also permits + /// address. + ///
+ ///

+ /// If set, the new list SHALL replace the existing list. public var gossipEndpoint: [Proto_ServiceEndpoint] = [] ///* - /// If set, replace the current list of service_endpoints. + /// A list of service endpoints for gRPC calls. + ///

+ /// If set, this list MUST meet the following requirements. + ///


+ /// These endpoints SHALL represent the published endpoints to which clients + /// may submit transactions.
+ /// These endpoints SHOULD specify address and port.
+ /// These endpoints MAY specify a DNS name.
+ /// These endpoints SHOULD NOT specify both address and DNS name.
+ /// This list MUST NOT be empty.
+ /// This list MUST NOT contain more than `8` entries. + ///

+ /// Each network may have additional requirements for these endpoints. + /// A client MUST check network-specific documentation for those + /// details. + ///

+ /// If set, the new list SHALL replace the existing list. public var serviceEndpoint: [Proto_ServiceEndpoint] = [] ///* - /// If set, the new X509 certificate of the gossip node. + /// A certificate used to sign gossip events. + ///

+ /// This value MUST be a certificate of a type permitted for gossip + /// signatures.
+ /// This value MUST be the DER encoding of the certificate presented. + ///

+ /// If set, the new value SHALL replace the existing bytes value. public var gossipCaCertificate: SwiftProtobuf.Google_Protobuf_BytesValue { get {return _gossipCaCertificate ?? SwiftProtobuf.Google_Protobuf_BytesValue()} set {_gossipCaCertificate = newValue} @@ -78,7 +150,16 @@ public struct Proto_NodeUpdateTransactionBody { public mutating func clearGossipCaCertificate() {self._gossipCaCertificate = nil} ///* - /// If set, the new grpc x509 certificate hash. + /// A hash of the node gRPC TLS certificate. + ///

+ /// This value MAY be used to verify the certificate presented by the node + /// during TLS negotiation for gRPC.
+ /// This value MUST be a SHA-384 hash.
+ /// The TLS certificate to be hashed MUST first be in PEM format and MUST be + /// encoded with UTF-8 NFKD encoding to a stream of bytes provided to + /// the hash algorithm.
+ ///

+ /// If set, the new value SHALL replace the existing hash value. public var grpcCertificateHash: SwiftProtobuf.Google_Protobuf_BytesValue { get {return _grpcCertificateHash ?? SwiftProtobuf.Google_Protobuf_BytesValue()} set {_grpcCertificateHash = newValue} @@ -88,6 +169,24 @@ public struct Proto_NodeUpdateTransactionBody { /// Clears the value of `grpcCertificateHash`. Subsequent reads from it will return its default value. public mutating func clearGrpcCertificateHash() {self._grpcCertificateHash = nil} + ///* + /// An administrative key controlled by the node operator. + ///

+ /// This field is OPTIONAL.
+ /// If set, this key MUST sign this transaction.
+ /// If set, this key MUST sign each subsequent transaction to + /// update this node.
+ /// If set, this field MUST contain a valid `Key` value.
+ /// If set, this field MUST NOT be set to an empty `KeyList`. + public var adminKey: Proto_Key { + get {return _adminKey ?? Proto_Key()} + set {_adminKey = newValue} + } + /// Returns true if `adminKey` has been explicitly set. + public var hasAdminKey: Bool {return self._adminKey != nil} + /// Clears the value of `adminKey`. Subsequent reads from it will return its default value. + public mutating func clearAdminKey() {self._adminKey = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -96,17 +195,18 @@ public struct Proto_NodeUpdateTransactionBody { fileprivate var _description_p: SwiftProtobuf.Google_Protobuf_StringValue? = nil fileprivate var _gossipCaCertificate: SwiftProtobuf.Google_Protobuf_BytesValue? = nil fileprivate var _grpcCertificateHash: SwiftProtobuf.Google_Protobuf_BytesValue? = nil + fileprivate var _adminKey: Proto_Key? = nil } #if swift(>=5.5) && canImport(_Concurrency) -extension Proto_NodeUpdateTransactionBody: @unchecked Sendable {} +extension Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. -fileprivate let _protobuf_package = "proto" +fileprivate let _protobuf_package = "com.hedera.hapi.node.addressbook" -extension Proto_NodeUpdateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".NodeUpdateTransactionBody" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "node_id"), @@ -116,6 +216,7 @@ extension Proto_NodeUpdateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf. 5: .standard(proto: "service_endpoint"), 6: .standard(proto: "gossip_ca_certificate"), 7: .standard(proto: "grpc_certificate_hash"), + 8: .standard(proto: "admin_key"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -131,6 +232,7 @@ extension Proto_NodeUpdateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf. case 5: try { try decoder.decodeRepeatedMessageField(value: &self.serviceEndpoint) }() case 6: try { try decoder.decodeSingularMessageField(value: &self._gossipCaCertificate) }() case 7: try { try decoder.decodeSingularMessageField(value: &self._grpcCertificateHash) }() + case 8: try { try decoder.decodeSingularMessageField(value: &self._adminKey) }() default: break } } @@ -162,10 +264,13 @@ extension Proto_NodeUpdateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf. try { if let v = self._grpcCertificateHash { try visitor.visitSingularMessageField(value: v, fieldNumber: 7) } }() + try { if let v = self._adminKey { + try visitor.visitSingularMessageField(value: v, fieldNumber: 8) + } }() try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Proto_NodeUpdateTransactionBody, rhs: Proto_NodeUpdateTransactionBody) -> Bool { + public static func ==(lhs: Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody, rhs: Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody) -> Bool { if lhs.nodeID != rhs.nodeID {return false} if lhs._accountID != rhs._accountID {return false} if lhs._description_p != rhs._description_p {return false} @@ -173,6 +278,7 @@ extension Proto_NodeUpdateTransactionBody: SwiftProtobuf.Message, SwiftProtobuf. if lhs.serviceEndpoint != rhs.serviceEndpoint {return false} if lhs._gossipCaCertificate != rhs._gossipCaCertificate {return false} if lhs._grpcCertificateHash != rhs._grpcCertificateHash {return false} + if lhs._adminKey != rhs._adminKey {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/HederaProtobufs/Services/query.pb.swift b/Sources/HederaProtobufs/Services/query.pb.swift index 0b407fd0..f2b92f9d 100644 --- a/Sources/HederaProtobufs/Services/query.pb.swift +++ b/Sources/HederaProtobufs/Services/query.pb.swift @@ -282,16 +282,6 @@ public struct Proto_Query { set {query = .accountDetails(newValue)} } - ///* - /// Get all information about a node - public var nodeGetInfo: Proto_NodeGetInfoQuery { - get { - if case .nodeGetInfo(let v)? = query {return v} - return Proto_NodeGetInfoQuery() - } - set {query = .nodeGetInfo(newValue)} - } - public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Query: Equatable { @@ -372,9 +362,6 @@ public struct Proto_Query { ///* /// Gets all information about an account including allowances granted by the account case accountDetails(Proto_GetAccountDetailsQuery) - ///* - /// Get all information about a node - case nodeGetInfo(Proto_NodeGetInfoQuery) #if !swift(>=4.1) public static func ==(lhs: Proto_Query.OneOf_Query, rhs: Proto_Query.OneOf_Query) -> Bool { @@ -482,10 +469,6 @@ public struct Proto_Query { guard case .accountDetails(let l) = lhs, case .accountDetails(let r) = rhs else { preconditionFailure() } return l == r }() - case (.nodeGetInfo, .nodeGetInfo): return { - guard case .nodeGetInfo(let l) = lhs, case .nodeGetInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() default: return false } } @@ -532,7 +515,6 @@ extension Proto_Query: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati 56: .same(proto: "tokenGetNftInfos"), 57: .same(proto: "networkGetExecutionTime"), 58: .same(proto: "accountDetails"), - 59: .same(proto: "nodeGetInfo"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -866,19 +848,6 @@ extension Proto_Query: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati self.query = .accountDetails(v) } }() - case 59: try { - var v: Proto_NodeGetInfoQuery? - var hadOneofValue = false - if let current = self.query { - hadOneofValue = true - if case .nodeGetInfo(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.query = .nodeGetInfo(v) - } - }() default: break } } @@ -990,10 +959,6 @@ extension Proto_Query: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati guard case .accountDetails(let v)? = self.query else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 58) }() - case .nodeGetInfo?: try { - guard case .nodeGetInfo(let v)? = self.query else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 59) - }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/HederaProtobufs/Services/response_code.pb.swift b/Sources/HederaProtobufs/Services/response_code.pb.swift index 7f1e292c..1585fd77 100644 --- a/Sources/HederaProtobufs/Services/response_code.pb.swift +++ b/Sources/HederaProtobufs/Services/response_code.pb.swift @@ -1212,36 +1212,118 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum { case tokenHasNoAdminKey // = 337 ///* - /// The node has been marked as deleted + /// A transaction failed because the consensus node identified is + /// deleted from the address book. case nodeDeleted // = 338 ///* - /// A node is not found during update and delete node transaction + /// A transaction failed because the consensus node identified is not valid or + /// does not exist in state. case invalidNodeID // = 339 ///* - /// gossip_endpoint has a fully qualified domain name instead of ip + /// A transaction failed because one or more entries in the list of + /// service endpoints for the `gossip_endpoint` field is invalid.
+ /// The most common cause for this response is a service endpoint that has + /// the domain name (DNS) set rather than address and port. case invalidGossipEndpoint // = 340 ///* - /// The node account_id is invalid + /// A transaction failed because the node account identifier provided + /// does not exist or is not valid.
+ /// One common source of this error is providing a node account identifier + /// using the "alias" form rather than "numeric" form. case invalidNodeAccountID // = 341 ///* - /// The node description is invalid + /// A transaction failed because the description field cannot be encoded + /// as UTF-8 or is more than 100 bytes when encoded. case invalidNodeDescription // = 342 ///* - /// service_endpoint is invalid + /// A transaction failed because one or more entries in the list of + /// service endpoints for the `service_endpoint` field is invalid.
+ /// The most common cause for this response is a service endpoint that has + /// the domain name (DNS) set rather than address and port. case invalidServiceEndpoint // = 343 ///* - /// gossip_ca_certificate is invalid - case invalidGossipCaeCertificate // = 344 + /// A transaction failed because the TLS certificate provided for the + /// node is missing or invalid.
+ /// The certificate MUST be a TLS certificate of a type permitted for gossip + /// signatures.
+ /// The value presented MUST be a UTF-8 NFKD encoding of the TLS + /// certificate.
+ /// The certificate encoded MUST be in PEM format.
+ /// The `gossip_ca_certificate` field is REQUIRED and MUST NOT be empty. + case invalidGossipCaCertificate // = 344 ///* - /// grpc_certificate_hash is invalid + /// A transaction failed because the hash provided for the gRPC certificate + /// is present but invalid.
+ /// The `grpc_certificate_hash` MUST be a SHA-384 hash.
+ /// The input hashed MUST be a UTF-8 NFKD encoding of the actual TLS + /// certificate.
+ /// The certificate to be encoded MUST be in PEM format. case invalidGrpcCertificate // = 345 + + ///* + /// The maximum automatic associations value is not valid.
+ /// The most common cause for this error is a value less than `-1`. + case invalidMaxAutoAssociations // = 346 + + ///* + /// The maximum number of nodes allowed in the address book have been created. + case maxNodesCreated // = 347 + + ///* + /// In ServiceEndpoint, domain_name and ipAddressV4 are mutually exclusive + case ipFqdnCannotBeSetForSameEndpoint // = 348 + + ///* + /// Fully qualified domain name is not allowed in gossip_endpoint + case gossipEndpointCannotHaveFqdn // = 349 + + ///* + /// In ServiceEndpoint, domain_name size too large + case fqdnSizeTooLarge // = 350 + + ///* + /// ServiceEndpoint is invalid + case invalidEndpoint // = 351 + + ///* + /// The number of gossip endpoints exceeds the limit + case gossipEndpointsExceededLimit // = 352 + + ///* + /// The transaction attempted to use duplicate `TokenReference`.
+ /// This affects `TokenReject` attempting to reject same token reference more than once. + case tokenReferenceRepeated // = 353 + + ///* + /// The account id specified as the owner in `TokenReject` is invalid or does not exist. + case invalidOwnerID // = 354 + + ///* + /// The transaction attempted to use more than the allowed number of `TokenReference`. + case tokenReferenceListSizeLimitExceeded // = 355 + + ///* + /// The number of service endpoints exceeds the limit + case serviceEndpointsExceededLimit // = 356 + + /// + /// The IPv4 address is invalid + case invalidIpv4Address // = 357 + + ///* + /// The transaction attempted to use empty `TokenReference` list. + case emptyTokenReferenceList // = 358 + + /// + /// The node account is not allowed to be updated + case updateNodeAccountNotAllowed // = 359 case UNRECOGNIZED(Int) public init() { @@ -1552,8 +1634,22 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum { case 341: self = .invalidNodeAccountID case 342: self = .invalidNodeDescription case 343: self = .invalidServiceEndpoint - case 344: self = .invalidGossipCaeCertificate + case 344: self = .invalidGossipCaCertificate case 345: self = .invalidGrpcCertificate + case 346: self = .invalidMaxAutoAssociations + case 347: self = .maxNodesCreated + case 348: self = .ipFqdnCannotBeSetForSameEndpoint + case 349: self = .gossipEndpointCannotHaveFqdn + case 350: self = .fqdnSizeTooLarge + case 351: self = .invalidEndpoint + case 352: self = .gossipEndpointsExceededLimit + case 353: self = .tokenReferenceRepeated + case 354: self = .invalidOwnerID + case 355: self = .tokenReferenceListSizeLimitExceeded + case 356: self = .serviceEndpointsExceededLimit + case 357: self = .invalidIpv4Address + case 358: self = .emptyTokenReferenceList + case 359: self = .updateNodeAccountNotAllowed default: self = .UNRECOGNIZED(rawValue) } } @@ -1862,8 +1958,22 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum { case .invalidNodeAccountID: return 341 case .invalidNodeDescription: return 342 case .invalidServiceEndpoint: return 343 - case .invalidGossipCaeCertificate: return 344 + case .invalidGossipCaCertificate: return 344 case .invalidGrpcCertificate: return 345 + case .invalidMaxAutoAssociations: return 346 + case .maxNodesCreated: return 347 + case .ipFqdnCannotBeSetForSameEndpoint: return 348 + case .gossipEndpointCannotHaveFqdn: return 349 + case .fqdnSizeTooLarge: return 350 + case .invalidEndpoint: return 351 + case .gossipEndpointsExceededLimit: return 352 + case .tokenReferenceRepeated: return 353 + case .invalidOwnerID: return 354 + case .tokenReferenceListSizeLimitExceeded: return 355 + case .serviceEndpointsExceededLimit: return 356 + case .invalidIpv4Address: return 357 + case .emptyTokenReferenceList: return 358 + case .updateNodeAccountNotAllowed: return 359 case .UNRECOGNIZED(let i): return i } } @@ -2177,8 +2287,22 @@ extension Proto_ResponseCodeEnum: CaseIterable { .invalidNodeAccountID, .invalidNodeDescription, .invalidServiceEndpoint, - .invalidGossipCaeCertificate, + .invalidGossipCaCertificate, .invalidGrpcCertificate, + .invalidMaxAutoAssociations, + .maxNodesCreated, + .ipFqdnCannotBeSetForSameEndpoint, + .gossipEndpointCannotHaveFqdn, + .fqdnSizeTooLarge, + .invalidEndpoint, + .gossipEndpointsExceededLimit, + .tokenReferenceRepeated, + .invalidOwnerID, + .tokenReferenceListSizeLimitExceeded, + .serviceEndpointsExceededLimit, + .invalidIpv4Address, + .emptyTokenReferenceList, + .updateNodeAccountNotAllowed, ] } @@ -2494,7 +2618,21 @@ extension Proto_ResponseCodeEnum: SwiftProtobuf._ProtoNameProviding { 341: .same(proto: "INVALID_NODE_ACCOUNT_ID"), 342: .same(proto: "INVALID_NODE_DESCRIPTION"), 343: .same(proto: "INVALID_SERVICE_ENDPOINT"), - 344: .same(proto: "INVALID_GOSSIP_CAE_CERTIFICATE"), + 344: .same(proto: "INVALID_GOSSIP_CA_CERTIFICATE"), 345: .same(proto: "INVALID_GRPC_CERTIFICATE"), + 346: .same(proto: "INVALID_MAX_AUTO_ASSOCIATIONS"), + 347: .same(proto: "MAX_NODES_CREATED"), + 348: .same(proto: "IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT"), + 349: .same(proto: "GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN"), + 350: .same(proto: "FQDN_SIZE_TOO_LARGE"), + 351: .same(proto: "INVALID_ENDPOINT"), + 352: .same(proto: "GOSSIP_ENDPOINTS_EXCEEDED_LIMIT"), + 353: .same(proto: "TOKEN_REFERENCE_REPEATED"), + 354: .same(proto: "INVALID_OWNER_ID"), + 355: .same(proto: "TOKEN_REFERENCE_LIST_SIZE_LIMIT_EXCEEDED"), + 356: .same(proto: "SERVICE_ENDPOINTS_EXCEEDED_LIMIT"), + 357: .same(proto: "INVALID_IPV4_ADDRESS"), + 358: .same(proto: "EMPTY_TOKEN_REFERENCE_LIST"), + 359: .same(proto: "UPDATE_NODE_ACCOUNT_NOT_ALLOWED"), ] } diff --git a/Sources/HederaProtobufs/Services/schedulable_transaction_body.pb.swift b/Sources/HederaProtobufs/Services/schedulable_transaction_body.pb.swift index abff0feb..6c153361 100644 --- a/Sources/HederaProtobufs/Services/schedulable_transaction_body.pb.swift +++ b/Sources/HederaProtobufs/Services/schedulable_transaction_body.pb.swift @@ -444,34 +444,58 @@ public struct Proto_SchedulableTransactionBody { ///* /// Transaction body for a scheduled transaction to create a new node. - public var nodeCreate: Proto_NodeCreateTransactionBody { + public var nodeCreate: Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody { get { if case .nodeCreate(let v)? = _storage._data {return v} - return Proto_NodeCreateTransactionBody() + return Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody() } set {_uniqueStorage()._data = .nodeCreate(newValue)} } ///* /// Transaction body for a scheduled transaction to modify an existing node. - public var nodeUpdate: Proto_NodeUpdateTransactionBody { + public var nodeUpdate: Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody { get { if case .nodeUpdate(let v)? = _storage._data {return v} - return Proto_NodeUpdateTransactionBody() + return Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody() } set {_uniqueStorage()._data = .nodeUpdate(newValue)} } ///* /// Transaction body for a scheduled transaction to remove a node. - public var nodeDelete: Proto_NodeDeleteTransactionBody { + public var nodeDelete: Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody { get { if case .nodeDelete(let v)? = _storage._data {return v} - return Proto_NodeDeleteTransactionBody() + return Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody() } set {_uniqueStorage()._data = .nodeDelete(newValue)} } + ///* + /// A transaction body to "reject" undesired tokens.
+ /// This transaction will transfer one or more tokens or token + /// balances held by the requesting account to the treasury + /// for each token type. + ///

+ /// Each transfer MUST be one of the following: + ///

+ /// When complete, the requesting account SHALL NOT hold the + /// rejected tokens.
+ /// Custom fees and royalties defined for the tokens rejected + /// SHALL NOT be charged for this transaction. + public var tokenReject: Proto_TokenRejectTransactionBody { + get { + if case .tokenReject(let v)? = _storage._data {return v} + return Proto_TokenRejectTransactionBody() + } + set {_uniqueStorage()._data = .tokenReject(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() ///* @@ -596,13 +620,30 @@ public struct Proto_SchedulableTransactionBody { case tokenUpdateNfts(Proto_TokenUpdateNftsTransactionBody) ///* /// Transaction body for a scheduled transaction to create a new node. - case nodeCreate(Proto_NodeCreateTransactionBody) + case nodeCreate(Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody) ///* /// Transaction body for a scheduled transaction to modify an existing node. - case nodeUpdate(Proto_NodeUpdateTransactionBody) + case nodeUpdate(Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody) ///* /// Transaction body for a scheduled transaction to remove a node. - case nodeDelete(Proto_NodeDeleteTransactionBody) + case nodeDelete(Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody) + ///* + /// A transaction body to "reject" undesired tokens.
+ /// This transaction will transfer one or more tokens or token + /// balances held by the requesting account to the treasury + /// for each token type. + ///

+ /// Each transfer MUST be one of the following: + ///

+ /// When complete, the requesting account SHALL NOT hold the + /// rejected tokens.
+ /// Custom fees and royalties defined for the tokens rejected + /// SHALL NOT be charged for this transaction. + case tokenReject(Proto_TokenRejectTransactionBody) #if !swift(>=4.1) public static func ==(lhs: Proto_SchedulableTransactionBody.OneOf_Data, rhs: Proto_SchedulableTransactionBody.OneOf_Data) -> Bool { @@ -778,6 +819,10 @@ public struct Proto_SchedulableTransactionBody { guard case .nodeDelete(let l) = lhs, case .nodeDelete(let r) = rhs else { preconditionFailure() } return l == r }() + case (.tokenReject, .tokenReject): return { + guard case .tokenReject(let l) = lhs, case .tokenReject(let r) = rhs else { preconditionFailure() } + return l == r + }() default: return false } } @@ -845,6 +890,7 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf 42: .same(proto: "nodeCreate"), 43: .same(proto: "nodeUpdate"), 44: .same(proto: "nodeDelete"), + 45: .same(proto: "tokenReject"), ] fileprivate class _StorageClass { @@ -1396,7 +1442,7 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf } }() case 42: try { - var v: Proto_NodeCreateTransactionBody? + var v: Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody? var hadOneofValue = false if let current = _storage._data { hadOneofValue = true @@ -1409,7 +1455,7 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf } }() case 43: try { - var v: Proto_NodeUpdateTransactionBody? + var v: Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody? var hadOneofValue = false if let current = _storage._data { hadOneofValue = true @@ -1422,7 +1468,7 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf } }() case 44: try { - var v: Proto_NodeDeleteTransactionBody? + var v: Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody? var hadOneofValue = false if let current = _storage._data { hadOneofValue = true @@ -1434,6 +1480,19 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf _storage._data = .nodeDelete(v) } }() + case 45: try { + var v: Proto_TokenRejectTransactionBody? + var hadOneofValue = false + if let current = _storage._data { + hadOneofValue = true + if case .tokenReject(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._data = .tokenReject(v) + } + }() default: break } } @@ -1621,6 +1680,10 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf guard case .nodeDelete(let v)? = _storage._data else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 44) }() + case .tokenReject?: try { + guard case .tokenReject(let v)? = _storage._data else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 45) + }() case nil: break } } diff --git a/Sources/HederaProtobufs/Services/state_addressbook_node.pb.swift b/Sources/HederaProtobufs/Services/state_addressbook_node.pb.swift index 6b6242c9..c49e519e 100644 --- a/Sources/HederaProtobufs/Services/state_addressbook_node.pb.swift +++ b/Sources/HederaProtobufs/Services/state_addressbook_node.pb.swift @@ -20,82 +20,35 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum Proto_NodeStatus: SwiftProtobuf.Enum { - public typealias RawValue = Int - - ///* - /// node in this state is deleted - case deleted // = 0 - - ///* - /// node in this state is waiting to be added by consensus roster - case pendingAddition // = 1 - - ///* - /// node in this state is waiting to be deleted by consensus roster - case pendingDeletion // = 2 - - ///* - /// node in this state is active on the network and participating - /// in network consensus. - case inConsensus // = 3 - case UNRECOGNIZED(Int) - - public init() { - self = .deleted - } - - public init?(rawValue: Int) { - switch rawValue { - case 0: self = .deleted - case 1: self = .pendingAddition - case 2: self = .pendingDeletion - case 3: self = .inConsensus - default: self = .UNRECOGNIZED(rawValue) - } - } - - public var rawValue: Int { - switch self { - case .deleted: return 0 - case .pendingAddition: return 1 - case .pendingDeletion: return 2 - case .inConsensus: return 3 - case .UNRECOGNIZED(let i): return i - } - } - -} - -#if swift(>=4.2) - -extension Proto_NodeStatus: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Proto_NodeStatus] = [ - .deleted, - .pendingAddition, - .pendingDeletion, - .inConsensus, - ] -} - -#endif // swift(>=4.2) - ///* -/// Representation of a Node in the network Merkle tree +/// A single address book node in the network state. +/// +/// Each node in the network address book SHALL represent a single actual +/// consensus node that is eligible to participate in network consensus. /// -/// A Node is identified by a single uint64 number, which is unique among all nodes. -public struct Proto_Node { +/// Address book nodes SHALL NOT be _globally_ uniquely identified. A given node +/// is only valid within a single realm and shard combination, so the identifier +/// for a network node SHALL only be unique within a single realm and shard +/// combination. +public struct Com_Hedera_Hapi_Node_State_Addressbook_Node { // 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 unique id of the Node. + /// A consensus node identifier. + ///

+ /// Node identifiers SHALL be unique _within_ a shard and realm, + /// but a node SHALL NOT, ever, serve multiple shards or realms, + /// therefore the node identifier MAY be repeated _between_ shards and realms. public var nodeID: UInt64 = 0 ///* - /// The account is charged for transactions submitted by the node that fail due diligence + /// An account identifier. + ///

+ /// This account SHALL be owned by the entity responsible for the node.
+ /// This account SHALL be charged transaction fees for any transactions that + /// are submitted to the network by this node and fail due diligence checks. public var accountID: Proto_AccountID { get {return _accountID ?? Proto_AccountID()} set {_accountID = newValue} @@ -106,59 +59,114 @@ public struct Proto_Node { public mutating func clearAccountID() {self._accountID = nil} ///* - /// A description of the node, with UTF-8 encoding up to 100 bytes + /// A short description of the node. + ///

+ /// This value, if set, SHALL NOT exceed 100 bytes when encoded as UTF-8. public var description_p: String = String() ///* - /// Node Gossip Endpoints, ip address or FQDN and port + /// A list of service endpoints for gossip. + ///

+ /// These endpoints SHALL represent the published endpoints to which other + /// consensus nodes may _gossip_ transactions.
+ /// If the network configuration value `gossipFqdnRestricted` is set, then + /// all endpoints in this list SHALL supply only IP address.
+ /// If the network configuration value `gossipFqdnRestricted` is _not_ set, + /// then endpoints in this list MAY supply either IP address or FQDN, but + /// SHALL NOT supply both values for the same endpoint.
+ /// This list SHALL NOT be empty.
+ /// This list SHALL NOT contain more than `10` entries.
+ /// The first two entries in this list SHALL be the endpoints published to + /// all consensus nodes.
+ /// All other entries SHALL be reserved for future use. public var gossipEndpoint: [Proto_ServiceEndpoint] = [] ///* - /// A node's service Endpoints, ip address or FQDN and port + /// A list of service endpoints for gRPC calls. + ///

+ /// These endpoints SHALL represent the published endpoints to which clients + /// may submit transactions.
+ /// These endpoints SHALL specify a port.
+ /// Endpoints in this list MAY supply either IP address or FQDN, but SHALL + /// NOT supply both values for the same endpoint.
+ /// This list SHALL NOT be empty.
+ /// This list SHALL NOT contain more than `8` entries. public var serviceEndpoint: [Proto_ServiceEndpoint] = [] ///* - /// The node's X509 certificate used to sign stream files (e.g., record stream - /// files). Precisely, this field is the DER encoding of gossip X509 certificate. + /// A certificate used to sign gossip events. + ///

+ /// This value SHALL be a certificate of a type permitted for gossip + /// signatures.
+ /// This value SHALL be the DER encoding of the certificate presented.
+ /// This field is REQUIRED and MUST NOT be empty. public var gossipCaCertificate: Data = Data() ///* - /// node x509 certificate hash. Hash of the node's TLS certificate. Precisely, this field is a string of - /// hexadecimal characters which, translated to binary, are the SHA-384 hash of - /// the UTF-8 NFKD encoding of the node's TLS cert in PEM format. Its value can be - /// used to verify the node's certificate it presents during TLS negotiations. + /// A hash of the node gRPC certificate. + ///

+ /// This value MAY be used to verify the certificate presented by the node + /// during TLS negotiation for gRPC.
+ /// This value SHALL be a SHA-384 hash.
+ /// The TLS certificate to be hashed SHALL first be in PEM format and SHALL + /// be encoded with UTF-8 NFKD encoding to a stream of bytes provided to + /// the hash algorithm.
+ /// This field is OPTIONAL. public var grpcCertificateHash: Data = Data() ///* - /// The consensus weight of this node in the network. + /// A consensus weight. + ///

+ /// Each node SHALL have a weight in consensus calculations.
+ /// The consensus weight of a node SHALL be calculated based on the amount + /// of HBAR staked to that node.
+ /// Consensus SHALL be calculated based on agreement of greater than `2/3` + /// of the total `weight` value of all nodes on the network. public var weight: UInt64 = 0 + ///* + /// A flag indicating this node is deleted. + ///

+ /// If this field is set, then this node SHALL NOT be included in the next + /// update of the network address book.
+ /// If this field is set, then this node SHALL be immutable and SHALL NOT + /// be modified.
+ /// If this field is set, then any `nodeUpdate` transaction to modify this + /// node SHALL fail. + public var deleted: Bool = false + + ///* + /// An administrative key controlled by the node operator. + ///

+ /// This key MUST sign each transaction to update this node.
+ /// This field MUST contain a valid `Key` value.
+ /// This field is REQUIRED and MUST NOT be set to an empty `KeyList`. + public var adminKey: Proto_Key { + get {return _adminKey ?? Proto_Key()} + set {_adminKey = newValue} + } + /// Returns true if `adminKey` has been explicitly set. + public var hasAdminKey: Bool {return self._adminKey != nil} + /// Clears the value of `adminKey`. Subsequent reads from it will return its default value. + public mutating func clearAdminKey() {self._adminKey = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} fileprivate var _accountID: Proto_AccountID? = nil + fileprivate var _adminKey: Proto_Key? = nil } #if swift(>=5.5) && canImport(_Concurrency) -extension Proto_NodeStatus: @unchecked Sendable {} -extension Proto_Node: @unchecked Sendable {} +extension Com_Hedera_Hapi_Node_State_Addressbook_Node: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. -fileprivate let _protobuf_package = "proto" +fileprivate let _protobuf_package = "com.hedera.hapi.node.state.addressbook" -extension Proto_NodeStatus: SwiftProtobuf._ProtoNameProviding { - public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "DELETED"), - 1: .same(proto: "PENDING_ADDITION"), - 2: .same(proto: "PENDING_DELETION"), - 3: .same(proto: "IN_CONSENSUS"), - ] -} - -extension Proto_Node: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Com_Hedera_Hapi_Node_State_Addressbook_Node: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Node" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "node_id"), @@ -169,6 +177,8 @@ extension Proto_Node: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio 6: .standard(proto: "gossip_ca_certificate"), 7: .standard(proto: "grpc_certificate_hash"), 8: .same(proto: "weight"), + 9: .same(proto: "deleted"), + 10: .standard(proto: "admin_key"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -185,6 +195,8 @@ extension Proto_Node: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio case 6: try { try decoder.decodeSingularBytesField(value: &self.gossipCaCertificate) }() case 7: try { try decoder.decodeSingularBytesField(value: &self.grpcCertificateHash) }() case 8: try { try decoder.decodeSingularUInt64Field(value: &self.weight) }() + case 9: try { try decoder.decodeSingularBoolField(value: &self.deleted) }() + case 10: try { try decoder.decodeSingularMessageField(value: &self._adminKey) }() default: break } } @@ -219,10 +231,16 @@ extension Proto_Node: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if self.weight != 0 { try visitor.visitSingularUInt64Field(value: self.weight, fieldNumber: 8) } + if self.deleted != false { + try visitor.visitSingularBoolField(value: self.deleted, fieldNumber: 9) + } + try { if let v = self._adminKey { + try visitor.visitSingularMessageField(value: v, fieldNumber: 10) + } }() try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Proto_Node, rhs: Proto_Node) -> Bool { + public static func ==(lhs: Com_Hedera_Hapi_Node_State_Addressbook_Node, rhs: Com_Hedera_Hapi_Node_State_Addressbook_Node) -> Bool { if lhs.nodeID != rhs.nodeID {return false} if lhs._accountID != rhs._accountID {return false} if lhs.description_p != rhs.description_p {return false} @@ -231,6 +249,8 @@ extension Proto_Node: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if lhs.gossipCaCertificate != rhs.gossipCaCertificate {return false} if lhs.grpcCertificateHash != rhs.grpcCertificateHash {return false} if lhs.weight != rhs.weight {return false} + if lhs.deleted != rhs.deleted {return false} + if lhs._adminKey != rhs._adminKey {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/HederaProtobufs/Services/token_reject.pb.swift b/Sources/HederaProtobufs/Services/token_reject.pb.swift new file mode 100644 index 00000000..7ba0aa9e --- /dev/null +++ b/Sources/HederaProtobufs/Services/token_reject.pb.swift @@ -0,0 +1,262 @@ +// DO NOT EDIT. +// swift-format-ignore-file +// +// Generated by the Swift generator plugin for the protocol buffer compiler. +// Source: token_reject.proto +// +// For information on using the generated types, please see the documentation: +// https://github.com/apple/swift-protobuf/ + +///* +/// # Token Reject +/// Messages used to implement a transaction to reject a token type from an +/// account. +/// +/// ### 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 +} + +///* +/// Reject undesired token(s).
+/// Transfer one or more token balances held by the requesting account to the treasury for each +/// token type.
+/// Each transfer SHALL be one of the following +/// - A single non-fungible/unique token. +/// - The full balance held for a fungible/common token type. +/// +/// A single tokenReject transaction SHALL support a maximum of 10 transfers. +/// +/// ### Transaction Record Effects +/// - Each successful transfer from `payer` to `treasury` SHALL be recorded in `token_transfer_list` for the transaction record. +public struct Proto_TokenRejectTransactionBody { + // 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 account holding the tokens to be rejected.
+ /// If set, this account MUST sign this transaction. + /// If not set, the payer for this transaction SHALL be the account rejecting tokens. + public var owner: Proto_AccountID { + get {return _owner ?? Proto_AccountID()} + set {_owner = newValue} + } + /// Returns true if `owner` has been explicitly set. + public var hasOwner: Bool {return self._owner != nil} + /// Clears the value of `owner`. Subsequent reads from it will return its default value. + public mutating func clearOwner() {self._owner = nil} + + ///* + /// A list of one or more token rejections.
+ /// On success each rejected token serial number or balance SHALL be transferred from + /// the requesting account to the treasury account for that token type.
+ /// After rejection the requesting account SHALL continue to be associated with the token.
+ /// if dissociation is desired then a separate TokenDissociate transaction MUST be submitted to remove the association. + public var rejections: [Proto_TokenReference] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _owner: Proto_AccountID? = nil +} + +///* +/// A union token identifier. +/// +/// Identify a fungible/common token type, or a single non-fungible/unique token serial. +public struct Proto_TokenReference { + // 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. + + public var tokenIdentifier: Proto_TokenReference.OneOf_TokenIdentifier? = nil + + ///* + /// A fungible/common token type. + public var fungibleToken: Proto_TokenID { + get { + if case .fungibleToken(let v)? = tokenIdentifier {return v} + return Proto_TokenID() + } + set {tokenIdentifier = .fungibleToken(newValue)} + } + + ///* + /// A single specific serialized non-fungible/unique token. + public var nft: Proto_NftID { + get { + if case .nft(let v)? = tokenIdentifier {return v} + return Proto_NftID() + } + set {tokenIdentifier = .nft(newValue)} + } + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public enum OneOf_TokenIdentifier: Equatable { + ///* + /// A fungible/common token type. + case fungibleToken(Proto_TokenID) + ///* + /// A single specific serialized non-fungible/unique token. + case nft(Proto_NftID) + + #if !swift(>=4.1) + public static func ==(lhs: Proto_TokenReference.OneOf_TokenIdentifier, rhs: Proto_TokenReference.OneOf_TokenIdentifier) -> 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 (.fungibleToken, .fungibleToken): return { + guard case .fungibleToken(let l) = lhs, case .fungibleToken(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.nft, .nft): return { + guard case .nft(let l) = lhs, case .nft(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif + } + + public init() {} +} + +#if swift(>=5.5) && canImport(_Concurrency) +extension Proto_TokenRejectTransactionBody: @unchecked Sendable {} +extension Proto_TokenReference: @unchecked Sendable {} +extension Proto_TokenReference.OneOf_TokenIdentifier: @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_TokenRejectTransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".TokenRejectTransactionBody" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "owner"), + 2: .same(proto: "rejections"), + ] + + 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._owner) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.rejections) }() + 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._owner { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + if !self.rejections.isEmpty { + try visitor.visitRepeatedMessageField(value: self.rejections, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_TokenRejectTransactionBody, rhs: Proto_TokenRejectTransactionBody) -> Bool { + if lhs._owner != rhs._owner {return false} + if lhs.rejections != rhs.rejections {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Proto_TokenReference: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".TokenReference" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "fungible_token"), + 2: .same(proto: "nft"), + ] + + 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 { + var v: Proto_TokenID? + var hadOneofValue = false + if let current = self.tokenIdentifier { + hadOneofValue = true + if case .fungibleToken(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.tokenIdentifier = .fungibleToken(v) + } + }() + case 2: try { + var v: Proto_NftID? + var hadOneofValue = false + if let current = self.tokenIdentifier { + hadOneofValue = true + if case .nft(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.tokenIdentifier = .nft(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 + switch self.tokenIdentifier { + case .fungibleToken?: try { + guard case .fungibleToken(let v)? = self.tokenIdentifier else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + }() + case .nft?: try { + guard case .nft(let v)? = self.tokenIdentifier else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + }() + case nil: break + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Proto_TokenReference, rhs: Proto_TokenReference) -> Bool { + if lhs.tokenIdentifier != rhs.tokenIdentifier {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/HederaProtobufs/Services/transaction_body.pb.swift b/Sources/HederaProtobufs/Services/transaction_body.pb.swift index 049a9842..2586b6b0 100644 --- a/Sources/HederaProtobufs/Services/transaction_body.pb.swift +++ b/Sources/HederaProtobufs/Services/transaction_body.pb.swift @@ -122,26 +122,6 @@ public struct Proto_TransactionBody { set {_uniqueStorage()._data = .contractUpdateInstance(newValue)} } - ///* - /// Delete contract and transfer remaining balance into specified account - public var contractDeleteInstance: Proto_ContractDeleteTransactionBody { - get { - if case .contractDeleteInstance(let v)? = _storage._data {return v} - return Proto_ContractDeleteTransactionBody() - } - set {_uniqueStorage()._data = .contractDeleteInstance(newValue)} - } - - ///* - /// An Ethereum encoded transaction. - public var ethereumTransaction: Proto_EthereumTransactionBody { - get { - if case .ethereumTransaction(let v)? = _storage._data {return v} - return Proto_EthereumTransactionBody() - } - set {_uniqueStorage()._data = .ethereumTransaction(newValue)} - } - ///* /// Attach a new livehash to an account public var cryptoAddLiveHash: Proto_CryptoAddLiveHashTransactionBody { @@ -152,26 +132,6 @@ public struct Proto_TransactionBody { set {_uniqueStorage()._data = .cryptoAddLiveHash(newValue)} } - ///* - /// Adds one or more approved allowances for spenders to transfer the paying account's hbar or tokens. - public var cryptoApproveAllowance: Proto_CryptoApproveAllowanceTransactionBody { - get { - if case .cryptoApproveAllowance(let v)? = _storage._data {return v} - return Proto_CryptoApproveAllowanceTransactionBody() - } - set {_uniqueStorage()._data = .cryptoApproveAllowance(newValue)} - } - - ///* - /// Deletes one or more of the specific approved NFT serial numbers on an owner account. - public var cryptoDeleteAllowance: Proto_CryptoDeleteAllowanceTransactionBody { - get { - if case .cryptoDeleteAllowance(let v)? = _storage._data {return v} - return Proto_CryptoDeleteAllowanceTransactionBody() - } - set {_uniqueStorage()._data = .cryptoDeleteAllowance(newValue)} - } - ///* /// Create a new cryptocurrency account public var cryptoCreateAccount: Proto_CryptoCreateTransactionBody { @@ -282,6 +242,16 @@ public struct Proto_TransactionBody { set {_uniqueStorage()._data = .systemUndelete(newValue)} } + ///* + /// Delete contract and transfer remaining balance into specified account + public var contractDeleteInstance: Proto_ContractDeleteTransactionBody { + get { + if case .contractDeleteInstance(let v)? = _storage._data {return v} + return Proto_ContractDeleteTransactionBody() + } + set {_uniqueStorage()._data = .contractDeleteInstance(newValue)} + } + ///* /// Freeze the nodes public var freeze: Proto_FreezeTransactionBody { @@ -462,6 +432,36 @@ public struct Proto_TransactionBody { set {_uniqueStorage()._data = .tokenDissociate(newValue)} } + ///* + /// Creates a schedule in the network's action queue + public var scheduleCreate: Proto_ScheduleCreateTransactionBody { + get { + if case .scheduleCreate(let v)? = _storage._data {return v} + return Proto_ScheduleCreateTransactionBody() + } + set {_uniqueStorage()._data = .scheduleCreate(newValue)} + } + + ///* + /// Deletes a schedule from the network's action queue + public var scheduleDelete: Proto_ScheduleDeleteTransactionBody { + get { + if case .scheduleDelete(let v)? = _storage._data {return v} + return Proto_ScheduleDeleteTransactionBody() + } + set {_uniqueStorage()._data = .scheduleDelete(newValue)} + } + + ///* + /// Adds one or more Ed25519 keys to the affirmed signers of a scheduled transaction + public var scheduleSign: Proto_ScheduleSignTransactionBody { + get { + if case .scheduleSign(let v)? = _storage._data {return v} + return Proto_ScheduleSignTransactionBody() + } + set {_uniqueStorage()._data = .scheduleSign(newValue)} + } + ///* /// Updates a token's custom fee schedule public var tokenFeeScheduleUpdate: Proto_TokenFeeScheduleUpdateTransactionBody { @@ -493,33 +493,33 @@ public struct Proto_TransactionBody { } ///* - /// Creates a schedule in the network's action queue - public var scheduleCreate: Proto_ScheduleCreateTransactionBody { + /// Adds one or more approved allowances for spenders to transfer the paying account's hbar or tokens. + public var cryptoApproveAllowance: Proto_CryptoApproveAllowanceTransactionBody { get { - if case .scheduleCreate(let v)? = _storage._data {return v} - return Proto_ScheduleCreateTransactionBody() + if case .cryptoApproveAllowance(let v)? = _storage._data {return v} + return Proto_CryptoApproveAllowanceTransactionBody() } - set {_uniqueStorage()._data = .scheduleCreate(newValue)} + set {_uniqueStorage()._data = .cryptoApproveAllowance(newValue)} } ///* - /// Deletes a schedule from the network's action queue - public var scheduleDelete: Proto_ScheduleDeleteTransactionBody { + /// Deletes one or more of the specific approved NFT serial numbers on an owner account. + public var cryptoDeleteAllowance: Proto_CryptoDeleteAllowanceTransactionBody { get { - if case .scheduleDelete(let v)? = _storage._data {return v} - return Proto_ScheduleDeleteTransactionBody() + if case .cryptoDeleteAllowance(let v)? = _storage._data {return v} + return Proto_CryptoDeleteAllowanceTransactionBody() } - set {_uniqueStorage()._data = .scheduleDelete(newValue)} + set {_uniqueStorage()._data = .cryptoDeleteAllowance(newValue)} } ///* - /// Adds one or more Ed25519 keys to the affirmed signers of a scheduled transaction - public var scheduleSign: Proto_ScheduleSignTransactionBody { + /// An Ethereum encoded transaction. + public var ethereumTransaction: Proto_EthereumTransactionBody { get { - if case .scheduleSign(let v)? = _storage._data {return v} - return Proto_ScheduleSignTransactionBody() + if case .ethereumTransaction(let v)? = _storage._data {return v} + return Proto_EthereumTransactionBody() } - set {_uniqueStorage()._data = .scheduleSign(newValue)} + set {_uniqueStorage()._data = .ethereumTransaction(newValue)} } ///* @@ -554,34 +554,67 @@ public struct Proto_TransactionBody { ///* /// A transaction body for a `createNode` request. - public var nodeCreate: Proto_NodeCreateTransactionBody { + ///

+ /// This transaction SHALL create a new consensus node record and add + /// that record to the network address book. + public var nodeCreate: Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody { get { if case .nodeCreate(let v)? = _storage._data {return v} - return Proto_NodeCreateTransactionBody() + return Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody() } set {_uniqueStorage()._data = .nodeCreate(newValue)} } ///* /// A transaction body for an `updateNode` request. - public var nodeUpdate: Proto_NodeUpdateTransactionBody { + ///

+ /// This transaction SHALL update an existing consensus node record in + /// the network address book. + public var nodeUpdate: Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody { get { if case .nodeUpdate(let v)? = _storage._data {return v} - return Proto_NodeUpdateTransactionBody() + return Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody() } set {_uniqueStorage()._data = .nodeUpdate(newValue)} } ///* /// A transaction body for a `deleteNode` request. - public var nodeDelete: Proto_NodeDeleteTransactionBody { + ///

+ /// This transaction SHALL remove an existing consensus node record from + /// the network address book. + public var nodeDelete: Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody { get { if case .nodeDelete(let v)? = _storage._data {return v} - return Proto_NodeDeleteTransactionBody() + return Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody() } set {_uniqueStorage()._data = .nodeDelete(newValue)} } + ///* + /// A transaction body to "reject" undesired tokens.
+ /// This transaction will transfer one or more tokens or token + /// balances held by the requesting account to the treasury + /// for each token type. + ///

+ /// Each transfer MUST be one of the following: + ///

+ /// When complete, the requesting account SHALL NOT hold the + /// rejected tokens.
+ /// Custom fees and royalties defined for the tokens rejected + /// SHALL NOT be charged for this transaction. + public var tokenReject: Proto_TokenRejectTransactionBody { + get { + if case .tokenReject(let v)? = _storage._data {return v} + return Proto_TokenRejectTransactionBody() + } + set {_uniqueStorage()._data = .tokenReject(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() ///* @@ -597,21 +630,9 @@ public struct Proto_TransactionBody { /// Updates a contract case contractUpdateInstance(Proto_ContractUpdateTransactionBody) ///* - /// Delete contract and transfer remaining balance into specified account - case contractDeleteInstance(Proto_ContractDeleteTransactionBody) - ///* - /// An Ethereum encoded transaction. - case ethereumTransaction(Proto_EthereumTransactionBody) - ///* /// Attach a new livehash to an account case cryptoAddLiveHash(Proto_CryptoAddLiveHashTransactionBody) ///* - /// Adds one or more approved allowances for spenders to transfer the paying account's hbar or tokens. - case cryptoApproveAllowance(Proto_CryptoApproveAllowanceTransactionBody) - ///* - /// Deletes one or more of the specific approved NFT serial numbers on an owner account. - case cryptoDeleteAllowance(Proto_CryptoDeleteAllowanceTransactionBody) - ///* /// Create a new cryptocurrency account case cryptoCreateAccount(Proto_CryptoCreateTransactionBody) ///* @@ -645,6 +666,9 @@ public struct Proto_TransactionBody { /// To undelete an entity deleted by SystemDelete case systemUndelete(Proto_SystemUndeleteTransactionBody) ///* + /// Delete contract and transfer remaining balance into specified account + case contractDeleteInstance(Proto_ContractDeleteTransactionBody) + ///* /// Freeze the nodes case freeze(Proto_FreezeTransactionBody) ///* @@ -699,6 +723,15 @@ public struct Proto_TransactionBody { /// Dissociate tokens from an account case tokenDissociate(Proto_TokenDissociateTransactionBody) ///* + /// Creates a schedule in the network's action queue + case scheduleCreate(Proto_ScheduleCreateTransactionBody) + ///* + /// Deletes a schedule from the network's action queue + case scheduleDelete(Proto_ScheduleDeleteTransactionBody) + ///* + /// Adds one or more Ed25519 keys to the affirmed signers of a scheduled transaction + case scheduleSign(Proto_ScheduleSignTransactionBody) + ///* /// Updates a token's custom fee schedule case tokenFeeScheduleUpdate(Proto_TokenFeeScheduleUpdateTransactionBody) ///* @@ -708,14 +741,14 @@ public struct Proto_TransactionBody { /// Unpauses the Token case tokenUnpause(Proto_TokenUnpauseTransactionBody) ///* - /// Creates a schedule in the network's action queue - case scheduleCreate(Proto_ScheduleCreateTransactionBody) + /// Adds one or more approved allowances for spenders to transfer the paying account's hbar or tokens. + case cryptoApproveAllowance(Proto_CryptoApproveAllowanceTransactionBody) ///* - /// Deletes a schedule from the network's action queue - case scheduleDelete(Proto_ScheduleDeleteTransactionBody) + /// Deletes one or more of the specific approved NFT serial numbers on an owner account. + case cryptoDeleteAllowance(Proto_CryptoDeleteAllowanceTransactionBody) ///* - /// Adds one or more Ed25519 keys to the affirmed signers of a scheduled transaction - case scheduleSign(Proto_ScheduleSignTransactionBody) + /// An Ethereum encoded transaction. + case ethereumTransaction(Proto_EthereumTransactionBody) ///* /// Updates the staking info at the end of staking period to indicate new staking period has started. case nodeStakeUpdate(Proto_NodeStakeUpdateTransactionBody) @@ -727,13 +760,39 @@ public struct Proto_TransactionBody { case tokenUpdateNfts(Proto_TokenUpdateNftsTransactionBody) ///* /// A transaction body for a `createNode` request. - case nodeCreate(Proto_NodeCreateTransactionBody) + ///

+ /// This transaction SHALL create a new consensus node record and add + /// that record to the network address book. + case nodeCreate(Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody) ///* /// A transaction body for an `updateNode` request. - case nodeUpdate(Proto_NodeUpdateTransactionBody) + ///

+ /// This transaction SHALL update an existing consensus node record in + /// the network address book. + case nodeUpdate(Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody) ///* /// A transaction body for a `deleteNode` request. - case nodeDelete(Proto_NodeDeleteTransactionBody) + ///

+ /// This transaction SHALL remove an existing consensus node record from + /// the network address book. + case nodeDelete(Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody) + ///* + /// A transaction body to "reject" undesired tokens.
+ /// This transaction will transfer one or more tokens or token + /// balances held by the requesting account to the treasury + /// for each token type. + ///

+ /// Each transfer MUST be one of the following: + ///

+ /// When complete, the requesting account SHALL NOT hold the + /// rejected tokens.
+ /// Custom fees and royalties defined for the tokens rejected + /// SHALL NOT be charged for this transaction. + case tokenReject(Proto_TokenRejectTransactionBody) #if !swift(>=4.1) public static func ==(lhs: Proto_TransactionBody.OneOf_Data, rhs: Proto_TransactionBody.OneOf_Data) -> Bool { @@ -753,26 +812,10 @@ public struct Proto_TransactionBody { guard case .contractUpdateInstance(let l) = lhs, case .contractUpdateInstance(let r) = rhs else { preconditionFailure() } return l == r }() - case (.contractDeleteInstance, .contractDeleteInstance): return { - guard case .contractDeleteInstance(let l) = lhs, case .contractDeleteInstance(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.ethereumTransaction, .ethereumTransaction): return { - guard case .ethereumTransaction(let l) = lhs, case .ethereumTransaction(let r) = rhs else { preconditionFailure() } - return l == r - }() case (.cryptoAddLiveHash, .cryptoAddLiveHash): return { guard case .cryptoAddLiveHash(let l) = lhs, case .cryptoAddLiveHash(let r) = rhs else { preconditionFailure() } return l == r }() - case (.cryptoApproveAllowance, .cryptoApproveAllowance): return { - guard case .cryptoApproveAllowance(let l) = lhs, case .cryptoApproveAllowance(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.cryptoDeleteAllowance, .cryptoDeleteAllowance): return { - guard case .cryptoDeleteAllowance(let l) = lhs, case .cryptoDeleteAllowance(let r) = rhs else { preconditionFailure() } - return l == r - }() case (.cryptoCreateAccount, .cryptoCreateAccount): return { guard case .cryptoCreateAccount(let l) = lhs, case .cryptoCreateAccount(let r) = rhs else { preconditionFailure() } return l == r @@ -817,6 +860,10 @@ public struct Proto_TransactionBody { guard case .systemUndelete(let l) = lhs, case .systemUndelete(let r) = rhs else { preconditionFailure() } return l == r }() + case (.contractDeleteInstance, .contractDeleteInstance): return { + guard case .contractDeleteInstance(let l) = lhs, case .contractDeleteInstance(let r) = rhs else { preconditionFailure() } + return l == r + }() case (.freeze, .freeze): return { guard case .freeze(let l) = lhs, case .freeze(let r) = rhs else { preconditionFailure() } return l == r @@ -889,6 +936,18 @@ public struct Proto_TransactionBody { guard case .tokenDissociate(let l) = lhs, case .tokenDissociate(let r) = rhs else { preconditionFailure() } return l == r }() + case (.scheduleCreate, .scheduleCreate): return { + guard case .scheduleCreate(let l) = lhs, case .scheduleCreate(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.scheduleDelete, .scheduleDelete): return { + guard case .scheduleDelete(let l) = lhs, case .scheduleDelete(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.scheduleSign, .scheduleSign): return { + guard case .scheduleSign(let l) = lhs, case .scheduleSign(let r) = rhs else { preconditionFailure() } + return l == r + }() case (.tokenFeeScheduleUpdate, .tokenFeeScheduleUpdate): return { guard case .tokenFeeScheduleUpdate(let l) = lhs, case .tokenFeeScheduleUpdate(let r) = rhs else { preconditionFailure() } return l == r @@ -901,16 +960,16 @@ public struct Proto_TransactionBody { guard case .tokenUnpause(let l) = lhs, case .tokenUnpause(let r) = rhs else { preconditionFailure() } return l == r }() - case (.scheduleCreate, .scheduleCreate): return { - guard case .scheduleCreate(let l) = lhs, case .scheduleCreate(let r) = rhs else { preconditionFailure() } + case (.cryptoApproveAllowance, .cryptoApproveAllowance): return { + guard case .cryptoApproveAllowance(let l) = lhs, case .cryptoApproveAllowance(let r) = rhs else { preconditionFailure() } return l == r }() - case (.scheduleDelete, .scheduleDelete): return { - guard case .scheduleDelete(let l) = lhs, case .scheduleDelete(let r) = rhs else { preconditionFailure() } + case (.cryptoDeleteAllowance, .cryptoDeleteAllowance): return { + guard case .cryptoDeleteAllowance(let l) = lhs, case .cryptoDeleteAllowance(let r) = rhs else { preconditionFailure() } return l == r }() - case (.scheduleSign, .scheduleSign): return { - guard case .scheduleSign(let l) = lhs, case .scheduleSign(let r) = rhs else { preconditionFailure() } + case (.ethereumTransaction, .ethereumTransaction): return { + guard case .ethereumTransaction(let l) = lhs, case .ethereumTransaction(let r) = rhs else { preconditionFailure() } return l == r }() case (.nodeStakeUpdate, .nodeStakeUpdate): return { @@ -937,6 +996,10 @@ public struct Proto_TransactionBody { guard case .nodeDelete(let l) = lhs, case .nodeDelete(let r) = rhs else { preconditionFailure() } return l == r }() + case (.tokenReject, .tokenReject): return { + guard case .tokenReject(let l) = lhs, case .tokenReject(let r) = rhs else { preconditionFailure() } + return l == r + }() default: return false } } @@ -969,11 +1032,7 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 7: .same(proto: "contractCall"), 8: .same(proto: "contractCreateInstance"), 9: .same(proto: "contractUpdateInstance"), - 22: .same(proto: "contractDeleteInstance"), - 50: .same(proto: "ethereumTransaction"), 10: .same(proto: "cryptoAddLiveHash"), - 48: .same(proto: "cryptoApproveAllowance"), - 49: .same(proto: "cryptoDeleteAllowance"), 11: .same(proto: "cryptoCreateAccount"), 12: .same(proto: "cryptoDelete"), 13: .same(proto: "cryptoDeleteLiveHash"), @@ -985,6 +1044,7 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 19: .same(proto: "fileUpdate"), 20: .same(proto: "systemDelete"), 21: .same(proto: "systemUndelete"), + 22: .same(proto: "contractDeleteInstance"), 23: .same(proto: "freeze"), 24: .same(proto: "consensusCreateTopic"), 25: .same(proto: "consensusUpdateTopic"), @@ -1003,18 +1063,22 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 39: .same(proto: "tokenWipe"), 40: .same(proto: "tokenAssociate"), 41: .same(proto: "tokenDissociate"), - 45: .standard(proto: "token_fee_schedule_update"), - 46: .standard(proto: "token_pause"), - 47: .standard(proto: "token_unpause"), 42: .same(proto: "scheduleCreate"), 43: .same(proto: "scheduleDelete"), 44: .same(proto: "scheduleSign"), + 45: .standard(proto: "token_fee_schedule_update"), + 46: .standard(proto: "token_pause"), + 47: .standard(proto: "token_unpause"), + 48: .same(proto: "cryptoApproveAllowance"), + 49: .same(proto: "cryptoDeleteAllowance"), + 50: .same(proto: "ethereumTransaction"), 51: .standard(proto: "node_stake_update"), 52: .standard(proto: "util_prng"), 53: .standard(proto: "token_update_nfts"), 54: .same(proto: "nodeCreate"), 55: .same(proto: "nodeUpdate"), 56: .same(proto: "nodeDelete"), + 57: .same(proto: "tokenReject"), ] fileprivate class _StorageClass { @@ -1669,7 +1733,7 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm } }() case 54: try { - var v: Proto_NodeCreateTransactionBody? + var v: Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody? var hadOneofValue = false if let current = _storage._data { hadOneofValue = true @@ -1682,7 +1746,7 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm } }() case 55: try { - var v: Proto_NodeUpdateTransactionBody? + var v: Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody? var hadOneofValue = false if let current = _storage._data { hadOneofValue = true @@ -1695,7 +1759,7 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm } }() case 56: try { - var v: Proto_NodeDeleteTransactionBody? + var v: Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody? var hadOneofValue = false if let current = _storage._data { hadOneofValue = true @@ -1707,6 +1771,19 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm _storage._data = .nodeDelete(v) } }() + case 57: try { + var v: Proto_TokenRejectTransactionBody? + var hadOneofValue = false + if let current = _storage._data { + hadOneofValue = true + if case .tokenReject(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._data = .tokenReject(v) + } + }() default: break } } @@ -1934,6 +2011,10 @@ extension Proto_TransactionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageIm guard case .nodeDelete(let v)? = _storage._data else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 56) }() + case .tokenReject?: try { + guard case .tokenReject(let v)? = _storage._data else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 57) + }() case nil: break } } diff --git a/Sources/HederaProtobufs/Services/transaction_receipt.pb.swift b/Sources/HederaProtobufs/Services/transaction_receipt.pb.swift index 8abf6d8d..fc098927 100644 --- a/Sources/HederaProtobufs/Services/transaction_receipt.pb.swift +++ b/Sources/HederaProtobufs/Services/transaction_receipt.pb.swift @@ -100,59 +100,65 @@ public struct Proto_TransactionReceipt { } ///* - /// In the receipt of a ConsensusSubmitMessage, the new running hash of the topic that received - /// the message. This 48-byte field is the output of a particular SHA-384 digest whose input - /// data are determined by the value of the topicRunningHashVersion below. The bytes of each - /// uint64 or uint32 are to be in Big-Endian format. - /// - /// IF the topicRunningHashVersion is '0' or '1', then the input data to the SHA-384 digest are, + /// In the receipt of a `ConsensusSubmitMessage`, the new running hash of the topic that + /// received the message.
+ /// This 48-byte field is the output of a SHA-384 digest with input data determined by the + /// value of the `topicRunningHashVersion` field.
+ /// All new transactions SHALL use `topicRunningHashVersion` `3`.
+ /// The bytes of each uint64 or uint32 encoded for the hash input MUST be in Big-Endian format. + ///

+ ///


+ /// If the `topicRunningHashVersion` is '0' or '1', then the input data to the SHA-384 digest are, /// in order: - /// --- - /// 1. The previous running hash of the topic (48 bytes) - /// 2. The topic's shard (8 bytes) - /// 3. The topic's realm (8 bytes) - /// 4. The topic's number (8 bytes) - /// 5. The number of seconds since the epoch before the ConsensusSubmitMessage reached - /// consensus (8 bytes) - /// 6. The number of nanoseconds since 5. before the ConsensusSubmitMessage reached - /// consensus (4 bytes) - /// 7. The topicSequenceNumber from above (8 bytes) - /// 8. The message bytes from the ConsensusSubmitMessage (variable). - /// - /// IF the topicRunningHashVersion is '2', then the input data to the SHA-384 digest are, in + ///
    + ///
  1. The previous running hash of the topic (48 bytes)
  2. + ///
  3. The topic's shard (8 bytes)
  4. + ///
  5. The topic's realm (8 bytes)
  6. + ///
  7. The topic's number (8 bytes)
  8. + ///
  9. The number of seconds since the epoch when the `ConsensusSubmitMessage` reached + /// consensus (8 bytes)
  10. + ///
  11. The number of nanoseconds within the second when the `ConsensusSubmitMessage` reached + /// consensus (4 bytes)
  12. + ///
  13. The `topicSequenceNumber` (8 bytes)
  14. + ///
  15. The message bytes from the `ConsensusSubmitMessage` (variable).
  16. + ///
+ ///
+ /// If the `topicRunningHashVersion` is '2', then the input data to the SHA-384 digest are, in /// order: - /// --- - /// 1. The previous running hash of the topic (48 bytes) - /// 2. The topicRunningHashVersion below (8 bytes) - /// 3. The topic's shard (8 bytes) - /// 4. The topic's realm (8 bytes) - /// 5. The topic's number (8 bytes) - /// 6. The number of seconds since the epoch before the ConsensusSubmitMessage reached - /// consensus (8 bytes) - /// 7. The number of nanoseconds since 6. before the ConsensusSubmitMessage reached - /// consensus (4 bytes) - /// 8. The topicSequenceNumber from above (8 bytes) - /// 9. The output of the SHA-384 digest of the message bytes from the - /// consensusSubmitMessage (48 bytes) - /// - /// Otherwise, IF the topicRunningHashVersion is '3', then the input data to the SHA-384 digest + ///
    + ///
  1. The previous running hash of the topic (48 bytes)
  2. + ///
  3. The `topicRunningHashVersion` (8 bytes)
  4. + ///
  5. The topic's shard (8 bytes)
  6. + ///
  7. The topic's realm (8 bytes)
  8. + ///
  9. The topic's number (8 bytes)
  10. + ///
  11. The number of seconds since the epoch when the `ConsensusSubmitMessage` reached + /// consensus (8 bytes)
  12. + ///
  13. The number of nanoseconds within the second when the `ConsensusSubmitMessage` reached + /// consensus (4 bytes)
  14. + ///
  15. The `topicSequenceNumber` (8 bytes)
  16. + ///
  17. The output of a SHA-384 digest of the message bytes from the `ConsensusSubmitMessage` + /// (48 bytes)
  18. + ///
+ ///
+ /// If the `topicRunningHashVersion` is '3', then the input data to the SHA-384 digest /// are, in order: - /// --- - /// 1. The previous running hash of the topic (48 bytes) - /// 2. The topicRunningHashVersion below (8 bytes) - /// 3. The payer account's shard (8 bytes) - /// 4. The payer account's realm (8 bytes) - /// 5. The payer account's number (8 bytes) - /// 6. The topic's shard (8 bytes) - /// 7. The topic's realm (8 bytes) - /// 8. The topic's number (8 bytes) - /// 9. The number of seconds since the epoch before the ConsensusSubmitMessage reached - /// consensus (8 bytes) - /// 10. The number of nanoseconds since 9. before the ConsensusSubmitMessage reached - /// consensus (4 bytes) - /// 11. The topicSequenceNumber from above (8 bytes) - /// 12. The output of the SHA-384 digest of the message bytes from the - /// consensusSubmitMessage (48 bytes) + ///
    + ///
  1. The previous running hash of the topic (48 bytes)
  2. + ///
  3. The `topicRunningHashVersion` (8 bytes)
  4. + ///
  5. The payer account's shard (8 bytes)
  6. + ///
  7. The payer account's realm (8 bytes)
  8. + ///
  9. The payer account's number (8 bytes)
  10. + ///
  11. The topic's shard (8 bytes)
  12. + ///
  13. The topic's realm (8 bytes)
  14. + ///
  15. The topic's number (8 bytes)
  16. + ///
  17. The number of seconds since the epoch when the `ConsensusSubmitMessage` reached + /// consensus (8 bytes)
  18. + ///
  19. The number of nanoseconds within the second when the `ConsensusSubmitMessage` reached + /// consensus (4 bytes)
  20. + ///
  21. The `topicSequenceNumber` (8 bytes)
  22. + ///
  23. The output of a SHA-384 digest of the message bytes from the `ConsensusSubmitMessage` + /// (48 bytes)
  24. + ///
public var topicRunningHash: Data { get {return _storage._topicRunningHash} set {_uniqueStorage()._topicRunningHash = newValue} @@ -220,6 +226,11 @@ public struct Proto_TransactionReceipt { ///* /// In the receipt of a NodeCreate, NodeUpdate, NodeDelete, the id of the newly created node. + /// An affected node identifier.
+ /// This value SHALL be set following a `createNode` transaction.
+ /// This value SHALL be set following a `updateNode` transaction.
+ /// This value SHALL be set following a `deleteNode` transaction.
+ /// This value SHALL NOT be set following any other transaction. public var nodeID: UInt64 { get {return _storage._nodeID} set {_uniqueStorage()._nodeID = newValue} diff --git a/Tests/HederaE2ETests/Account/Account.swift b/Tests/HederaE2ETests/Account/Account.swift index a5f41a7e..5fd875ff 100644 --- a/Tests/HederaE2ETests/Account/Account.swift +++ b/Tests/HederaE2ETests/Account/Account.swift @@ -39,6 +39,25 @@ internal struct Account { return Self(id: id, key: key) } + internal static func create( + _ testEnv: NonfreeTestEnvironment, _ accountKey: Key, _ maxAutomaticTokenAssociations: Int32 + ) async throws -> Self { + let key = PrivateKey.generateEd25519() + + try await testEnv.ratelimits.accountCreate() + + let receipt = try await AccountCreateTransaction() + .key(accountKey) + .initialBalance(Hbar(1)) + .maxAutomaticTokenAssociations(maxAutomaticTokenAssociations) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let id = try XCTUnwrap(receipt.accountId) + + return Self(id: id, key: key) + } + internal func delete(_ testEnv: NonfreeTestEnvironment) async throws { _ = try await AccountDeleteTransaction() .accountId(id) diff --git a/Tests/HederaE2ETests/Account/AccountUpdate.swift b/Tests/HederaE2ETests/Account/AccountUpdate.swift index 1ed07182..dee2a561 100644 --- a/Tests/HederaE2ETests/Account/AccountUpdate.swift +++ b/Tests/HederaE2ETests/Account/AccountUpdate.swift @@ -88,4 +88,56 @@ internal final class AccountUpdate: XCTestCase { XCTAssertEqual(status, .accountIDDoesNotExist) } } + + internal func testCannotUpdateTokenMaxAssociationToLowerValueFails() async throws { + let testEnv = try TestEnvironment.nonFree + + let accountKey = PrivateKey.generateEd25519() + + // Create account with max token associations of 1 + let accountCreateReceipt = try await AccountCreateTransaction() + .key(.single(accountKey.publicKey)) + .maxAutomaticTokenAssociations(1) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let accountId = try XCTUnwrap(accountCreateReceipt.accountId) + + // Create token + let tokenCreateReceipt = try await TokenCreateTransaction() + .name("ffff") + .symbol("F") + .initialSupply(100_000) + .treasuryAccountId(testEnv.operator.accountId) + .adminKey(.single(testEnv.operator.privateKey.publicKey)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let tokenId = try XCTUnwrap(tokenCreateReceipt.tokenId) + + // Associate token with account + let _ = try await TransferTransaction() + .tokenTransfer(tokenId, testEnv.operator.accountId, -10) + .tokenTransfer(tokenId, accountId, 10) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + await assertThrowsHErrorAsync( + // Update account max token associations to 0 + try await AccountUpdateTransaction() + .accountId(accountId) + .maxAutomaticTokenAssociations(0) + .freezeWith(testEnv.client) + .sign(accountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .existingAutomaticAssociationsExceedGivenLimit) + } + } } diff --git a/Tests/HederaE2ETests/Contract/ContractCreate.swift b/Tests/HederaE2ETests/Contract/ContractCreate.swift index 1f32ce5b..3efd1ccf 100644 --- a/Tests/HederaE2ETests/Contract/ContractCreate.swift +++ b/Tests/HederaE2ETests/Contract/ContractCreate.swift @@ -92,12 +92,11 @@ internal final class ContractCreate: XCTestCase { .constructorParameters(ContractFunctionParameters().addString("Hello from Hedera.")) .bytecodeFileId(bytecode.fileId) .contractMemo("[e2e::ContractCreateTransaction]") - .execute(testEnv.client) - .getReceipt(testEnv.client), + .execute(testEnv.client), "expected error creating contract" ) { error in - guard case .receiptStatus(let status, transactionId: _) = error.kind else { - XCTFail("`\(error.kind)` is not `.receiptStatus`") + guard case .transactionPreCheckStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.transactionPreCheckStatus`") return } diff --git a/Tests/HederaE2ETests/Token/FungibleToken.swift b/Tests/HederaE2ETests/Token/FungibleToken.swift index 0465989f..b22d0c2d 100644 --- a/Tests/HederaE2ETests/Token/FungibleToken.swift +++ b/Tests/HederaE2ETests/Token/FungibleToken.swift @@ -27,31 +27,63 @@ internal struct FungibleToken { internal static func create( _ testEnv: NonfreeTestEnvironment, - owner: Account, + owner: Account? = nil, initialSupply: UInt64 = 0 ) async throws -> Self { - let metadataKey = PrivateKey.generateEd25519() - let ownerKey = Key.single(owner.key.publicKey) - let receipt = try await TokenCreateTransaction( - name: "ffff", - symbol: "f", - decimals: 3, - initialSupply: initialSupply, - treasuryAccountId: owner.id, - adminKey: ownerKey, - kycKey: ownerKey, - freezeKey: ownerKey, - wipeKey: ownerKey, - supplyKey: ownerKey, - freezeDefault: false, - expirationTime: .now + .minutes(5), - feeScheduleKey: ownerKey, - pauseKey: ownerKey, - metadataKey: Key.single(metadataKey.publicKey) - ) - .sign(owner.key) - .execute(testEnv.client) - .getReceipt(testEnv.client) + let privateKey = owner?.key ?? testEnv.operator.privateKey + let owner = owner ?? Account(id: testEnv.operator.accountId, key: testEnv.operator.privateKey) + + let receipt = try await TokenCreateTransaction() + .name("ffff") + .symbol("f") + .tokenMemo("e2e test") + .expirationTime(.now + .minutes(5)) + .decimals(3) + .initialSupply(initialSupply) + .treasuryAccountId(owner.id) + .adminKey(.single(privateKey.publicKey)) + .freezeKey(.single(privateKey.publicKey)) + .wipeKey(.single(privateKey.publicKey)) + .supplyKey(.single(privateKey.publicKey)) + .metadataKey(.single(privateKey.publicKey)) + .pauseKey(.single(privateKey.publicKey)) + .kycKey(.single(privateKey.publicKey)) + .feeScheduleKey(.single(privateKey.publicKey)) + .freezeDefault(false) + .freezeWith(testEnv.client) + .sign(privateKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let id = try XCTUnwrap(receipt.tokenId) + + return Self(id: id, owner: owner) + } + + internal static func create( + _ testEnv: NonfreeTestEnvironment, + decimals: UInt32 + ) async throws -> Self { + let owner = Account(id: testEnv.operator.accountId, key: testEnv.operator.privateKey) + + let receipt = try await TokenCreateTransaction() + .name("ffff") + .symbol("f") + .tokenMemo("e2e test") + .expirationTime(.now + .minutes(5)) + .decimals(decimals) + .initialSupply(1_000_000) + .maxSupply(1_000_000) + .treasuryAccountId(testEnv.operator.accountId) + .tokenSupplyType(.finite) + .adminKey(.single(testEnv.operator.privateKey.publicKey)) + .freezeKey(.single(testEnv.operator.privateKey.publicKey)) + .wipeKey(.single(testEnv.operator.privateKey.publicKey)) + .supplyKey(.single(testEnv.operator.privateKey.publicKey)) + .metadataKey(.single(testEnv.operator.privateKey.publicKey)) + .pauseKey(.single(testEnv.operator.privateKey.publicKey)) + .execute(testEnv.client) + .getReceipt(testEnv.client) let id = try XCTUnwrap(receipt.tokenId) diff --git a/Tests/HederaE2ETests/Token/Nft.swift b/Tests/HederaE2ETests/Token/Nft.swift index 4efe68af..88c515c0 100644 --- a/Tests/HederaE2ETests/Token/Nft.swift +++ b/Tests/HederaE2ETests/Token/Nft.swift @@ -25,20 +25,23 @@ internal struct Nft { internal let id: TokenId internal let owner: Account - internal static func create(_ testEnv: NonfreeTestEnvironment, owner: Account) async throws -> Self { - let ownerKey = Key.single(owner.key.publicKey) + internal static func create(_ testEnv: NonfreeTestEnvironment, owner: Account? = nil) async throws -> Self { + let owner = owner ?? Account(id: testEnv.operator.accountId, key: testEnv.operator.privateKey) + let receipt = try await TokenCreateTransaction( name: "ffff", symbol: "f", treasuryAccountId: owner.id, - adminKey: ownerKey, - freezeKey: ownerKey, - wipeKey: ownerKey, - supplyKey: ownerKey, + adminKey: Key.single(owner.key.publicKey), + freezeKey: Key.single(owner.key.publicKey), + wipeKey: Key.single(owner.key.publicKey), + supplyKey: Key.single(owner.key.publicKey), freezeDefault: false, expirationTime: .now + .minutes(5), tokenType: .nonFungibleUnique, - feeScheduleKey: ownerKey + feeScheduleKey: Key.single(owner.key.publicKey), + pauseKey: Key.single(owner.key.publicKey), + metadataKey: Key.single(owner.key.publicKey) ) .sign(owner.key) .execute(testEnv.client) diff --git a/Tests/HederaE2ETests/Token/TokenReject.swift b/Tests/HederaE2ETests/Token/TokenReject.swift new file mode 100644 index 00000000..7e66d478 --- /dev/null +++ b/Tests/HederaE2ETests/Token/TokenReject.swift @@ -0,0 +1,721 @@ +/* + * ‌ + * 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 Hedera +import XCTest + +internal class TokenReject: XCTestCase { + internal func testBasicFtReject() async throws { + let testEnv = try TestEnvironment.nonFree + + let ft1 = try await FungibleToken.create(testEnv, decimals: 3) + let ft2 = try await FungibleToken.create(testEnv, decimals: 3) + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), 100) + + let _ = try await TransferTransaction() + .tokenTransfer(ft1.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft1.id, receiverAccount.id, 10) + .tokenTransfer(ft2.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft2.id, receiverAccount.id, 10) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TokenRejectTransaction() + .owner(receiverAccount.id) + .tokenIds([ft1.id, ft2.id]) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let receiverBalance = try await AccountBalanceQuery() + .accountId(receiverAccount.id) + .execute(testEnv.client) + + XCTAssertEqual(receiverBalance.tokenBalances[ft1.id], 0) + XCTAssertEqual(receiverBalance.tokenBalances[ft2.id], 0) + + let treasuryAccountBalance = try await AccountBalanceQuery() + .accountId(testEnv.operator.accountId) + .execute(testEnv.client) + + XCTAssertEqual(treasuryAccountBalance.tokenBalances[ft1.id], 1_000_000) + XCTAssertEqual(treasuryAccountBalance.tokenBalances[ft2.id], 1_000_000) + + addTeardownBlock { + try await ft1.delete(testEnv) + try await ft2.delete(testEnv) + } + } + + internal func testBasicNftReject() async throws { + let testEnv = try TestEnvironment.nonFree + + let nft1 = try await Nft.create(testEnv) + let nft2 = try await Nft.create(testEnv) + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), 100) + + let _ = try await TokenMintTransaction() + .tokenId(nft1.id) + .metadata(Array(repeating: Data([9, 1, 6]), count: 5)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftMintReceipt2 = try await TokenMintTransaction() + .tokenId(nft2.id) + .metadata(Array(repeating: Data([3, 6, 9]), count: 5)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftSerials = try XCTUnwrap(nftMintReceipt2.serials) + + let _ = try await TransferTransaction() + .nftTransfer(nft1.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft1.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft2.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft2.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TokenRejectTransaction() + .owner(receiverAccount.id) + .nftIds([nft1.id.nft(nftSerials[1]), nft2.id.nft(nftSerials[1])]) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nft1Info = try await TokenNftInfoQuery() + .nftId(nft1.id.nft(nftSerials[1])) + .execute(testEnv.client) + + XCTAssertEqual(nft1Info.accountId, testEnv.operator.accountId) + + let nft2Info = try await TokenNftInfoQuery() + .nftId(nft2.id.nft(nftSerials[1])) + .execute(testEnv.client) + + XCTAssertEqual(nft2Info.accountId, testEnv.operator.accountId) + + addTeardownBlock { + try await nft1.delete(testEnv) + try await nft2.delete(testEnv) + } + } + + internal func testFtAndNftReject() async throws { + let testEnv = try TestEnvironment.nonFree + + let ft1 = try await FungibleToken.create(testEnv, decimals: 3) + let ft2 = try await FungibleToken.create(testEnv, decimals: 3) + let nft1 = try await Nft.create(testEnv) + let nft2 = try await Nft.create(testEnv) + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), 100) + + let _ = try await TokenMintTransaction() + .tokenId(nft1.id) + .metadata(Array(repeating: Data([9, 1, 6]), count: 5)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftMintReceipt2 = try await TokenMintTransaction() + .tokenId(nft2.id) + .metadata(Array(repeating: Data([3, 6, 9]), count: 5)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftSerials = try XCTUnwrap(nftMintReceipt2.serials) + + let _ = try await TransferTransaction() + .tokenTransfer(ft1.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft1.id, receiverAccount.id, 10) + .tokenTransfer(ft2.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft2.id, receiverAccount.id, 10) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TransferTransaction() + .nftTransfer(nft1.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft1.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft2.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft2.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TokenRejectTransaction() + .owner(receiverAccount.id) + .tokenIds([ft1.id, ft2.id]) + .nftIds([nft1.id.nft(nftSerials[1]), nft2.id.nft(nftSerials[1])]) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let receiverAccountBalance = try await AccountBalanceQuery() + .accountId(receiverAccount.id) + .execute(testEnv.client) + + XCTAssertEqual(receiverAccountBalance.tokenBalances[ft1.id], 0) + XCTAssertEqual(receiverAccountBalance.tokenBalances[ft2.id], 0) + XCTAssertEqual(receiverAccountBalance.tokenBalances[nft1.id], 1) + XCTAssertEqual(receiverAccountBalance.tokenBalances[nft2.id], 1) + + let treasuryAccountBalance = try await AccountBalanceQuery() + .accountId(testEnv.operator.accountId) + .execute(testEnv.client) + + XCTAssertEqual(treasuryAccountBalance.tokenBalances[ft1.id], 1_000_000) + XCTAssertEqual(treasuryAccountBalance.tokenBalances[ft2.id], 1_000_000) + + let nft1Info = try await TokenNftInfoQuery() + .nftId(nft1.id.nft(nftSerials[1])) + .execute(testEnv.client) + + XCTAssertEqual(nft1Info.accountId, testEnv.operator.accountId) + + let nft2Info = try await TokenNftInfoQuery() + .nftId(nft2.id.nft(nftSerials[1])) + .execute(testEnv.client) + + XCTAssertEqual(nft2Info.accountId, testEnv.operator.accountId) + + addTeardownBlock { + try await ft1.delete(testEnv) + try await ft2.delete(testEnv) + try await nft1.delete(testEnv) + try await nft2.delete(testEnv) + } + } + + internal func testFtAndNftFreeze() async throws { + let testEnv = try TestEnvironment.nonFree + + let ft1 = try await FungibleToken.create(testEnv, decimals: 3) + let ft2 = try await FungibleToken.create(testEnv, decimals: 3) + let nft1 = try await Nft.create(testEnv) + let nft2 = try await Nft.create(testEnv) + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), 100) + + let _ = try await TokenMintTransaction() + .tokenId(nft1.id) + .metadata(Array(repeating: Data([9, 1, 6]), count: 5)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftMintReceipt2 = try await TokenMintTransaction() + .tokenId(nft2.id) + .metadata(Array(repeating: Data([3, 6, 9]), count: 5)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftSerials = try XCTUnwrap(nftMintReceipt2.serials) + + let _ = try await TransferTransaction() + .tokenTransfer(ft1.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft1.id, receiverAccount.id, 10) + .tokenTransfer(ft2.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft2.id, receiverAccount.id, 10) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TransferTransaction() + .nftTransfer(nft1.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft1.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft2.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft2.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TokenRejectTransaction() + .owner(receiverAccount.id) + .tokenIds([ft1.id, ft2.id]) + .nftIds([nft1.id.nft(nftSerials[1]), nft2.id.nft(nftSerials[1])]) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let receiverAccountBalance = try await AccountBalanceQuery() + .accountId(receiverAccount.id) + .execute(testEnv.client) + + XCTAssertEqual(receiverAccountBalance.tokenBalances[ft1.id], 0) + XCTAssertEqual(receiverAccountBalance.tokenBalances[ft2.id], 0) + XCTAssertEqual(receiverAccountBalance.tokenBalances[nft1.id], 1) + XCTAssertEqual(receiverAccountBalance.tokenBalances[nft2.id], 1) + + let treasuryAccountBalance = try await AccountBalanceQuery() + .accountId(testEnv.operator.accountId) + .execute(testEnv.client) + + XCTAssertEqual(treasuryAccountBalance.tokenBalances[ft1.id], 1_000_000) + XCTAssertEqual(treasuryAccountBalance.tokenBalances[ft2.id], 1_000_000) + + let nft1Info = try await TokenNftInfoQuery() + .nftId(nft1.id.nft(nftSerials[1])) + .execute(testEnv.client) + + XCTAssertEqual(nft1Info.accountId, testEnv.operator.accountId) + + let nft2Info = try await TokenNftInfoQuery() + .nftId(nft2.id.nft(nftSerials[1])) + .execute(testEnv.client) + + XCTAssertEqual(nft2Info.accountId, testEnv.operator.accountId) + + addTeardownBlock { + try await ft1.delete(testEnv) + try await ft2.delete(testEnv) + try await nft1.delete(testEnv) + try await nft2.delete(testEnv) + } + } + + internal func testFtAndNftPaused() async throws { + let testEnv = try TestEnvironment.nonFree + + let ft = try await FungibleToken.create(testEnv, decimals: 3) + let nft = try await Nft.create(testEnv) + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), 100) + + let _ = try await TransferTransaction() + .tokenTransfer(ft.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft.id, receiverAccount.id, 10) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TokenPauseTransaction() + .tokenId(ft.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(receiverAccount.id) + .addTokenId(ft.id) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .tokenIsPaused) + } + + let mintReceipt = try await TokenMintTransaction() + .tokenId(nft.id) + .metadata(Array(repeating: Data([9, 1, 6]), count: 5)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftSerials = try XCTUnwrap(mintReceipt.serials) + + let _ = try await TransferTransaction() + .nftTransfer(nft.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TokenPauseTransaction() + .tokenId(nft.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(receiverAccount.id) + .addNftId(nft.id.nft(nftSerials[1])) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .tokenIsPaused) + } + } + + internal func testRemoveAllowance() async throws { + let testEnv = try TestEnvironment.nonFree + + let ft = try await FungibleToken.create(testEnv, decimals: 3) + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), 100) + + let spenderAccountKey = PrivateKey.generateEd25519() + let spenderCreateReceipt = try await AccountCreateTransaction() + .key(.single(spenderAccountKey.publicKey)) + .initialBalance(Hbar(1)) + .maxAutomaticTokenAssociations(-1) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let spenderAccountId = try XCTUnwrap(spenderCreateReceipt.accountId) + + let _ = try await TransferTransaction() + .tokenTransfer(ft.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft.id, receiverAccount.id, 10) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await AccountAllowanceApproveTransaction() + .approveTokenAllowance(ft.id, receiverAccount.id, spenderAccountId, 10) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TransferTransaction() + .approvedTokenTransfer(ft.id, receiverAccount.id, -5) + .tokenTransfer(ft.id, spenderAccountId, 5) + .transactionId(TransactionId.generateFrom(spenderAccountId)) + .freezeWith(testEnv.client) + .sign(spenderAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TokenRejectTransaction() + .owner(receiverAccount.id) + .addTokenId(ft.id) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + await assertThrowsHErrorAsync( + try await TransferTransaction() + .approvedTokenTransfer(ft.id, receiverAccount.id, -5) + .tokenTransfer(ft.id, spenderAccountId, 5) + .transactionId(TransactionId.generateFrom(spenderAccountId)) + .freezeWith(testEnv.client) + .sign(spenderAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .spenderDoesNotHaveAllowance) + } + + let nft = try await Nft.create(testEnv) + + let mintReceipt = try await TokenMintTransaction() + .tokenId(nft.id) + .metadata(Array(repeating: Data([4, 2, 0]), count: 4)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftSerials = try XCTUnwrap(mintReceipt.serials) + + let _ = try await TransferTransaction() + .nftTransfer(nft.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[2]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[3]), testEnv.operator.accountId, receiverAccount.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await AccountAllowanceApproveTransaction() + .approveTokenNftAllowance(nft.id.nft(nftSerials[0]), receiverAccount.id, spenderAccountId) + .approveTokenNftAllowance(nft.id.nft(nftSerials[1]), receiverAccount.id, spenderAccountId) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TransferTransaction() + .approvedNftTransfer(nft.id.nft(nftSerials[0]), receiverAccount.id, spenderAccountId) + .transactionId(TransactionId.generateFrom(spenderAccountId)) + .freezeWith(testEnv.client) + .sign(spenderAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let _ = try await TokenRejectTransaction() + .owner(receiverAccount.id) + .nftIds([nft.id.nft(nftSerials[1]), nft.id.nft(nftSerials[2])]) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + await assertThrowsHErrorAsync( + try await TransferTransaction() + .approvedNftTransfer(nft.id.nft(nftSerials[1]), receiverAccount.id, spenderAccountId) + .approvedNftTransfer(nft.id.nft(nftSerials[2]), receiverAccount.id, spenderAccountId) + .transactionId(TransactionId.generateFrom(spenderAccountId)) + .freezeWith(testEnv.client) + .sign(spenderAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .spenderDoesNotHaveAllowance) + } + + addTeardownBlock { + try await ft.delete(testEnv) + try await nft.delete(testEnv) + } + } + + internal func testAddOrSetNftTokenIdFail() async throws { + let testEnv = try TestEnvironment.nonFree + + let nft = try await Nft.create(testEnv) + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), 100) + + let mintReceipt = try await TokenMintTransaction() + .tokenId(nft.id) + .metadata(Array(repeating: Data([4, 2, 0]), count: 4)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftSerials = try XCTUnwrap(mintReceipt.serials) + + let _ = try await TransferTransaction() + .nftTransfer(nft.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[2]), testEnv.operator.accountId, receiverAccount.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(receiverAccount.id) + .addTokenId(nft.id) + .nftIds([nft.id.nft(nftSerials[1]), nft.id.nft(nftSerials[2])]) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .accountAmountTransfersOnlyAllowedForFungibleCommon) + } + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(receiverAccount.id) + .tokenIds([nft.id]) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .accountAmountTransfersOnlyAllowedForFungibleCommon) + } + + addTeardownBlock { + try await nft.delete(testEnv) + } + } + + internal func testTreasuryFail() async throws { + let testEnv = try TestEnvironment.nonFree + + let ft = try await FungibleToken.create(testEnv, decimals: 3) + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(testEnv.operator.accountId) + .addTokenId(ft.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .accountIsTreasury) + } + + let nft = try await Nft.create(testEnv) + + let mintReceipt = try await TokenMintTransaction() + .tokenId(nft.id) + .metadata(Array(repeating: Data([4, 2, 0]), count: 4)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftSerials = try XCTUnwrap(mintReceipt.serials) + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(testEnv.operator.accountId) + .addNftId(nft.id.nft(nftSerials[0])) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .accountIsTreasury) + } + } + + internal func testInvalidSigFail() async throws { + let testEnv = try TestEnvironment.nonFree + + let ft = try await FungibleToken.create(testEnv, decimals: 3) + let randomKey = PrivateKey.generateEd25519() + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), 100) + + let _ = try await TransferTransaction() + .tokenTransfer(ft.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft.id, receiverAccount.id, 10) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(receiverAccount.id) + .addTokenId(ft.id) + .freezeWith(testEnv.client) + .sign(randomKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .invalidSignature) + } + + addTeardownBlock { + try await ft.delete(testEnv) + } + } + + internal func testMissingTokenFail() async throws { + let testEnv = try TestEnvironment.nonFree + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(testEnv.operator.accountId) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .transactionPreCheckStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.transactionPreCheckStatus`") + return + } + + XCTAssertEqual(status, .emptyTokenReferenceList) + } + } + + internal func testTokenReferenceListSizeExceededFail() async throws { + let testEnv = try TestEnvironment.nonFree + + let ft = try await FungibleToken.create(testEnv, decimals: 3) + let nft = try await Nft.create(testEnv) + let receiverAccountKey = PrivateKey.generateEd25519() + let receiverAccount = try await Account.create(testEnv, Key.single(receiverAccountKey.publicKey), -1) + + let mintReceipt = try await TokenMintTransaction() + .tokenId(nft.id) + .metadata(Array(repeating: Data([9, 1, 6]), count: 10)) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + let nftSerials = try XCTUnwrap(mintReceipt.serials) + + let _ = try await TransferTransaction() + .tokenTransfer(ft.id, testEnv.operator.accountId, -10) + .tokenTransfer(ft.id, receiverAccount.id, 10) + .nftTransfer(nft.id.nft(nftSerials[0]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[1]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[2]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[3]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[4]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[5]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[6]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[7]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[8]), testEnv.operator.accountId, receiverAccount.id) + .nftTransfer(nft.id.nft(nftSerials[9]), testEnv.operator.accountId, receiverAccount.id) + .execute(testEnv.client) + .getReceipt(testEnv.client) + + await assertThrowsHErrorAsync( + try await TokenRejectTransaction() + .owner(receiverAccount.id) + .addTokenId(ft.id) + .nftIds([ + nft.id.nft(nftSerials[0]), nft.id.nft(nftSerials[1]), nft.id.nft(nftSerials[2]), + nft.id.nft(nftSerials[3]), nft.id.nft(nftSerials[4]), nft.id.nft(nftSerials[5]), + nft.id.nft(nftSerials[6]), nft.id.nft(nftSerials[7]), nft.id.nft(nftSerials[8]), + nft.id.nft(nftSerials[9]), + ]) + .freezeWith(testEnv.client) + .sign(receiverAccountKey) + .execute(testEnv.client) + .getReceipt(testEnv.client) + ) { error in + guard case .receiptStatus(let status, transactionId: _) = error.kind else { + XCTFail("`\(error.kind)` is not `.receiptStatus`") + return + } + + XCTAssertEqual(status, .tokenReferenceListSizeLimitExceeded) + } + + addTeardownBlock { + try await nft.delete(testEnv) + try await ft.delete(testEnv) + } + } +} diff --git a/Tests/HederaTests/AccountCreateTransactionTests.swift b/Tests/HederaTests/AccountCreateTransactionTests.swift index cd6666a3..29fdfeea 100644 --- a/Tests/HederaTests/AccountCreateTransactionTests.swift +++ b/Tests/HederaTests/AccountCreateTransactionTests.swift @@ -26,7 +26,7 @@ import XCTest internal class AccountCreateTransactionTests: XCTestCase { private static let testKey = Key.single(Resources.publicKey) - private static let testMaxAutomaticTokenAssociations: UInt32 = 101 + private static let testMaxAutomaticTokenAssociations: Int32 = 101 private static let testAutoRenewPeriod = Duration.hours(10) private static let testAutoRenewAccountId: AccountId = 30 private static let testStakedAccountId: AccountId = 3 @@ -126,7 +126,7 @@ internal class AccountCreateTransactionTests: XCTestCase { proto.key = Self.testKey.toProtobuf() proto.stakedNodeID = Int64(Self.testStakedNodeId) proto.stakedAccountID = Self.testStakedAccountId.toProtobuf() - proto.maxAutomaticTokenAssociations = Int32(Self.testMaxAutomaticTokenAssociations) + proto.maxAutomaticTokenAssociations = Self.testMaxAutomaticTokenAssociations } let protoBody = Proto_TransactionBody.with { proto in diff --git a/Tests/HederaTests/ContractCreateTransactionTests.swift b/Tests/HederaTests/ContractCreateTransactionTests.swift index 1d744c96..abf32565 100644 --- a/Tests/HederaTests/ContractCreateTransactionTests.swift +++ b/Tests/HederaTests/ContractCreateTransactionTests.swift @@ -29,7 +29,7 @@ internal class ContractCreateTransactionTests: XCTestCase { private static let adminKey = Key.single(Resources.publicKey) private static let gas: UInt64 = 0 private static let initialBalance = Hbar.fromTinybars(1000) - private static let maxAutomaticTokenAssociations: UInt32 = 101 + private static let maxAutomaticTokenAssociations: Int32 = 101 private static let autoRenewPeriod = Duration.hours(10) private static let constructorParameters = Data([10, 11, 12, 13, 25]) private static let autoRenewAccountId: AccountId = 30 @@ -104,7 +104,7 @@ internal class ContractCreateTransactionTests: XCTestCase { proto.adminKey = Self.adminKey.toProtobuf() proto.gas = Int64(Self.gas) proto.initialBalance = Self.initialBalance.toTinybars() - proto.maxAutomaticTokenAssociations = Int32(Self.maxAutomaticTokenAssociations) + proto.maxAutomaticTokenAssociations = Self.maxAutomaticTokenAssociations proto.autoRenewPeriod = Self.autoRenewPeriod.toProtobuf() proto.constructorParameters = Self.constructorParameters proto.autoRenewAccountID = Self.autoRenewAccountId.toProtobuf() diff --git a/Tests/HederaTests/ContractUpdateTransactionTests.swift b/Tests/HederaTests/ContractUpdateTransactionTests.swift index 9634b3ce..8d685ac6 100644 --- a/Tests/HederaTests/ContractUpdateTransactionTests.swift +++ b/Tests/HederaTests/ContractUpdateTransactionTests.swift @@ -27,7 +27,7 @@ import XCTest internal final class ContractUpdateTransactionTests: XCTestCase { private static let contractId: ContractId = "0.0.5007" private static let adminKey = Key.single(Resources.publicKey) - private static let maxAutomaticTokenAssociations: UInt32 = 101 + private static let maxAutomaticTokenAssociations: Int32 = 101 private static let autoRenewPeriod = Duration.days(1) private static let contractMemo = "3" private static let expirationTime = Timestamp(seconds: 1_554_158_543, subSecondNanos: 0) @@ -102,7 +102,7 @@ internal final class ContractUpdateTransactionTests: XCTestCase { let protoData = Proto_ContractUpdateTransactionBody.with { proto in proto.contractID = Self.contractId.toProtobuf() proto.adminKey = Self.adminKey.toProtobuf() - proto.maxAutomaticTokenAssociations = .init(Int32(Self.maxAutomaticTokenAssociations)) + proto.maxAutomaticTokenAssociations = .init(Self.maxAutomaticTokenAssociations) proto.autoRenewPeriod = Self.autoRenewPeriod.toProtobuf() proto.memoWrapper = .init(Self.contractMemo) proto.expirationTime = Self.expirationTime.toProtobuf() diff --git a/Tests/HederaTests/TokenRejectTransaction.swift b/Tests/HederaTests/TokenRejectTransaction.swift new file mode 100644 index 00000000..9a777c9f --- /dev/null +++ b/Tests/HederaTests/TokenRejectTransaction.swift @@ -0,0 +1,127 @@ +/* + * ‌ + * 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 HederaProtobufs +import SnapshotTesting +import XCTest + +@testable import Hedera + +internal final class TokenRejectTransactionTests: XCTestCase { + private static let testPrivateKey = PrivateKey( + "302e020100300506032b657004220420db484b828e64b2d8f12ce3c0a0e93a0b8cce7af1bb8f39c97732394482538e10") + private static let testOwnerId = AccountId("0.0.12345") + + private static let testTokenIds: [TokenId] = [TokenId("4.2.0"), TokenId("4.2.1"), TokenId("4.2.2")] + + private static let testNftIds: [NftId] = [NftId("4.2.3/1"), NftId("4.2.4/2"), NftId("4.2.5/3")] + + private static func makeTransaction() throws -> TokenRejectTransaction { + try TokenRejectTransaction() + .nodeAccountIds(Resources.nodeAccountIds) + .transactionId(Resources.txId) + .owner(testOwnerId) + .tokenIds(testTokenIds) + .nftIds(testNftIds) + .freeze() + .sign(testPrivateKey) + } + + 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 { + var protoTokenReferences: [Proto_TokenReference] = [] + + for tokenId in Self.testTokenIds { + protoTokenReferences.append(.with { $0.fungibleToken = tokenId.toProtobuf() }) + } + + for nftId in Self.testNftIds { + protoTokenReferences.append(.with { $0.nft = nftId.toProtobuf() }) + } + + let protoData = Proto_TokenRejectTransactionBody.with { proto in + proto.owner = Self.testOwnerId.toProtobuf() + proto.rejections = protoTokenReferences + } + + let protoBody = Proto_TransactionBody.with { proto in + proto.tokenReject = protoData + proto.transactionID = Resources.txId.toProtobuf() + } + + let tx = try TokenRejectTransaction(protobuf: protoBody, protoData) + + XCTAssertEqual(tx.owner, Self.testOwnerId) + XCTAssertEqual(tx.tokenIds, Self.testTokenIds) + XCTAssertEqual(tx.nftIds, Self.testNftIds) + } + + internal func testGetSetOwner() { + let tx = TokenRejectTransaction() + tx.owner(Self.testOwnerId) + + XCTAssertEqual(tx.owner, Self.testOwnerId) + } + + internal func testGetSetTokenIds() { + let tx = TokenRejectTransaction() + tx.tokenIds(Self.testTokenIds) + + XCTAssertEqual(tx.tokenIds, Self.testTokenIds) + } + + internal func testGetSetNftIds() { + let tx = TokenRejectTransaction() + tx.nftIds(Self.testNftIds) + + XCTAssertEqual(tx.nftIds, Self.testNftIds) + } + + internal func testGetSetAddTokenId() { + let tx = TokenRejectTransaction() + tx.addTokenId(Self.testTokenIds[0]) + tx.addTokenId(Self.testTokenIds[1]) + + XCTAssertEqual(tx.tokenIds[0], Self.testTokenIds[0]) + XCTAssertEqual(tx.tokenIds[1], Self.testTokenIds[1]) + } + + internal func testGetSetAddNftId() { + let tx = TokenRejectTransaction() + tx.addNftId(Self.testNftIds[0]) + tx.addNftId(Self.testNftIds[1]) + + XCTAssertEqual(tx.nftIds[0], Self.testNftIds[0]) + XCTAssertEqual(tx.nftIds[1], Self.testNftIds[1]) + } +} diff --git a/Tests/HederaTests/__Snapshots__/TokenRejectTransaction/testSerialize.1.txt b/Tests/HederaTests/__Snapshots__/TokenRejectTransaction/testSerialize.1.txt new file mode 100644 index 00000000..b4892b77 --- /dev/null +++ b/Tests/HederaTests/__Snapshots__/TokenRejectTransaction/testSerialize.1.txt @@ -0,0 +1,71 @@ +HederaProtobufs.Proto_TransactionBody: +transactionID { + transactionValidStart { + seconds: 1554158542 + } + accountID { + accountNum: 5006 + } +} +nodeAccountID { + accountNum: 5005 +} +transactionFee: 200000000 +transactionValidDuration { + seconds: 120 +} +tokenReject { + owner { + accountNum: 12345 + } + rejections { + fungible_token { + shardNum: 4 + realmNum: 2 + } + } + rejections { + fungible_token { + shardNum: 4 + realmNum: 2 + tokenNum: 1 + } + } + rejections { + fungible_token { + shardNum: 4 + realmNum: 2 + tokenNum: 2 + } + } + rejections { + nft { + token_ID { + shardNum: 4 + realmNum: 2 + tokenNum: 3 + } + serial_number: 1 + } + } + rejections { + nft { + token_ID { + shardNum: 4 + realmNum: 2 + tokenNum: 4 + } + serial_number: 2 + } + } + rejections { + nft { + token_ID { + shardNum: 4 + realmNum: 2 + tokenNum: 5 + } + serial_number: 3 + } + } +} diff --git a/protobufs b/protobufs index 17fb1486..f3ebaed1 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 17fb148652b1e2badda1c5cdff531f0fcf7f4c55 +Subproject commit f3ebaed10173a074931650a546dd89dbc3d87cd8