From c8d5f76cfa40798a371b64b0a0109a026088a9fd Mon Sep 17 00:00:00 2001 From: Kristy Brambila Date: Mon, 13 Jan 2020 16:57:00 -0800 Subject: [PATCH] Implement Hbar type --- Sources/Hedera/Client.swift | 11 +-- Sources/Hedera/Hbar.swift | 66 +++++++++++++++++ Sources/Hedera/HbarUnit.swift | 73 +++++++++++++++++++ Sources/Hedera/QueryBuilder.swift | 23 +++--- Sources/Hedera/TransactionBuilder.swift | 6 +- Sources/Hedera/TransactionRecord.swift | 26 +------ .../Hedera/account/AccountBalanceQuery.swift | 6 +- .../account/AccountCreateTransaction.swift | 21 +++--- Sources/Hedera/account/AccountInfo.swift | 16 ++-- Sources/Hedera/account/AccountInfoQuery.swift | 8 ++ .../account/AccountUpdateTransaction.swift | 8 +- .../account/CryptoTransferTransaction.swift | 14 ++-- .../contract/ContractCreateTransaction.swift | 7 +- .../contract/ContractExecuteTransaction.swift | 6 +- .../Hedera/contract/ContractInfoQuery.swift | 9 ++- Sources/Hedera/file/FileInfoQuery.swift | 8 ++ 16 files changed, 228 insertions(+), 80 deletions(-) create mode 100644 Sources/Hedera/Hbar.swift create mode 100644 Sources/Hedera/HbarUnit.swift diff --git a/Sources/Hedera/Client.swift b/Sources/Hedera/Client.swift index 53e144b7..0fa6e476 100644 --- a/Sources/Hedera/Client.swift +++ b/Sources/Hedera/Client.swift @@ -1,6 +1,7 @@ import Sodium import GRPC import NIO +import Foundation struct Node { let accountId: AccountId @@ -21,9 +22,9 @@ typealias HederaGRPCClient = (fileService: Proto_FileServiceServiceClient, cryptoService: Proto_CryptoServiceServiceClient, contractService: Proto_SmartContractServiceServiceClient) -let defaultMaxTransactionFee: UInt64 = 100_000_000 // 1h +let defaultMaxTransactionFee = Hbar(hbar: Decimal(1))! // 1h -let defaultMaxQueryPayment: UInt64 = 100_000_000 // 1h +let defaultMaxQueryPayment = Hbar(hbar: Decimal(1))! // 1h public class Client { var `operator`: Operator? @@ -93,11 +94,11 @@ public class Client { /// This can be overridden for an individual transaction with `.setTransactionFee()`. /// /// - Parameters: - /// - max: The maximum transaction fee, in tinybars. + /// - max: The maximum transaction fee. /// /// - Returns: Self for fluent usage. @discardableResult - public func setMaxTransactionFee(_ max: UInt64) -> Self { + public func setMaxTransactionFee(_ max: Hbar) -> Self { maxTransactionFee = max return self } @@ -110,7 +111,7 @@ public class Client { /// /// - Returns: Self for fluent usage. @discardableResult - public func setMaxQueryPayment(_ max: UInt64) -> Self { + public func setMaxQueryPayment(_ max: Hbar) -> Self { maxQueryPayment = max return self } diff --git a/Sources/Hedera/Hbar.swift b/Sources/Hedera/Hbar.swift new file mode 100644 index 00000000..f00c367d --- /dev/null +++ b/Sources/Hedera/Hbar.swift @@ -0,0 +1,66 @@ +import Foundation + +public struct Hbar { + private let tinybar: Int64 + + private init(tinybar: Int64) { + self.tinybar = tinybar + } + + public static let MAX = Hbar(tinybar: Int64.max) + public static let MIN = Hbar(tinybar: Int64.min) + public static let ZERO = Hbar(tinybar: 0) + + public init?(hbar: Decimal) { + let tinybarAmount = hbar * HbarUnit.Hbar.toTinybarCount() + guard let tinybar = Int64(exactly: NSDecimalNumber(decimal: tinybarAmount)) else { return nil } + + self.init(tinybar: tinybar) + } + + public static func from(amount: Decimal, unit: HbarUnit) -> Self? { + guard let tinybar = Int64(exactly: NSDecimalNumber(decimal: amount * unit.toTinybarCount())) else { return nil } + + return Self(tinybar: tinybar) + } + + public static func from(amount: Int64, unit: HbarUnit) -> Self? { + guard let tinybar = Int64(exactly: NSDecimalNumber(decimal: Decimal(amount) * unit.toTinybarCount())) else { return nil } + + return Self(tinybar: tinybar) + } + + public static func fromTinybar(amount: Int64) -> Self { + Self(tinybar: amount) + } + + public func `as`(unit: HbarUnit) -> Decimal { + if unit == .Tinybar { + return Decimal(tinybar) + } + return Decimal(tinybar) / unit.toTinybarCount() + } + + public func asTinybar() -> Int64 { + return tinybar + } +} + +extension Hbar: CustomStringConvertible { + public var description: String { + if Decimal(tinybar) < HbarUnit.Hbar.toTinybarCount() { + return "\(tinybar) \(HbarUnit.Tinybar.getSymbol)" + } + return "\(Decimal(tinybar) / HbarUnit.Hbar.toTinybarCount()) \(HbarUnit.Hbar.getSymbol) (\(tinybar) tinybar)" + } +} + +extension Hbar: Comparable { + public static func < (lhs: Hbar, rhs: Hbar) -> Bool { + return lhs.tinybar < rhs.tinybar + } + + public static func == (lhs: Hbar, rhs: Hbar) -> Bool { + return lhs.tinybar == rhs.tinybar + } +} diff --git a/Sources/Hedera/HbarUnit.swift b/Sources/Hedera/HbarUnit.swift new file mode 100644 index 00000000..f7a1f25a --- /dev/null +++ b/Sources/Hedera/HbarUnit.swift @@ -0,0 +1,73 @@ +import Foundation + +public enum HbarUnit { + case Tinybar + case Microbar + case Millibar + case Hbar + case Kilobar + case Megabar + case Gigabar + + public var getSymbol: String { + switch self { + case .Tinybar: + return "tℏ" + case .Microbar: + return "μℏ" + case .Millibar: + return "mℏ" + case .Hbar: + return "ℏ" + case .Kilobar: + return "kℏ" + case .Megabar: + return "Mℏ" + case .Gigabar: + return "Gℏ" + } + } + + func toTinybarCount() -> Decimal { + let amount: UInt64 + switch self { + case .Tinybar: + amount = 1 + case .Microbar: + amount = 100 + case .Millibar: + amount = 100_000 + case .Hbar: + amount = 100_000_000 + case .Kilobar: + amount = 100_000_000 * 1_000 + case .Megabar: + amount = 100_000_000 * 1_000_000 + case .Gigabar: + amount = 100_000_000 * 1_000_000_000 + } + + return Decimal(amount) + } +} + +extension HbarUnit: CustomStringConvertible { + public var description: String { + switch self { + case .Tinybar: + return "tinybar" + case .Microbar: + return "microbar" + case .Millibar: + return "millibar" + case .Hbar: + return "hbar" + case .Kilobar: + return "kilobar" + case .Megabar: + return "megabar" + case .Gigabar: + return "gigabar" + } + } +} diff --git a/Sources/Hedera/QueryBuilder.swift b/Sources/Hedera/QueryBuilder.swift index 37153e48..35839817 100644 --- a/Sources/Hedera/QueryBuilder.swift +++ b/Sources/Hedera/QueryBuilder.swift @@ -10,19 +10,19 @@ public class QueryBuilder { // var header = Proto_QueryHeader() var needsPayment: Bool { true } - var maxQueryPayment: UInt64? - var queryPayment: UInt64? + var maxQueryPayment: Hbar? + var queryPayment: Hbar? init() {} @discardableResult - public func setMaxQueryPayment(_ max: UInt64) -> Self { + public func setMaxQueryPayment(_ max: Hbar) -> Self { maxQueryPayment = max return self } @discardableResult - public func setQueryPayment(_ amount: UInt64) -> Self { + public func setQueryPayment(_ amount: Hbar) -> Self { queryPayment = amount return self } @@ -37,7 +37,7 @@ public class QueryBuilder { } @discardableResult - func getCost(client: Client, node: Node) -> EventLoopFuture { + func getCost(client: Client, node: Node) -> EventLoopFuture { // Store the current response type and payment let responseType = withHeader { $0.responseType } let payment = withHeader { $0.payment } @@ -57,14 +57,15 @@ public class QueryBuilder { // COST_ANSWER requires a 0 payment and does not actually process it $0.payment = CryptoTransferTransaction() - .addSender(client.operator!.id, amount: 0) - .addRecipient(node.accountId, amount: 0) + .addSender(client.operator!.id, amount: Hbar.ZERO) + .addRecipient(node.accountId, amount: Hbar.ZERO) .build(client: client) .addSigPair(publicKey: client.operator!.publicKey, signer: client.operator!.signer) .toProto() } let eventLoop = client.eventLoopGroup.next() + let successValueMapper = { Hbar.fromTinybar(amount: Int64(self.getResponseHeader($0).cost)) } return self.getQueryMethod(client.grpcClient(for: node))(self.body, nil) .response @@ -79,11 +80,11 @@ public class QueryBuilder { node: node, startTime: Date(), attempt: 0, - successValueMapper: { self.getResponseHeader($0).cost } + successValueMapper: successValueMapper ) } - switch resultFromCode(code, success: { header.cost }) { + switch resultFromCode(code, success: { successValueMapper(resp) }) { case .success(let res): return eventLoop.makeSucceededFuture(res) @@ -94,7 +95,7 @@ public class QueryBuilder { } @discardableResult - public func getCost(client: Client) -> EventLoopFuture { + public func getCost(client: Client) -> EventLoopFuture { return getCost(client: client, node: client.pickNode()) } @@ -162,7 +163,7 @@ public class QueryBuilder { } } - func generateQueryPaymentTransaction(client: Client, node: Node, amount: UInt64) { + func generateQueryPaymentTransaction(client: Client, node: Node, amount: Hbar) { let tx = CryptoTransferTransaction() .setNodeAccountId(node.accountId) .addSender(client.operator!.id, amount: amount) diff --git a/Sources/Hedera/TransactionBuilder.swift b/Sources/Hedera/TransactionBuilder.swift index a6ac6a3b..8cb32fed 100644 --- a/Sources/Hedera/TransactionBuilder.swift +++ b/Sources/Hedera/TransactionBuilder.swift @@ -20,8 +20,8 @@ public class TransactionBuilder { } @discardableResult - public func setMaxTransactionFee(_ fee: UInt64) -> Self { - body.transactionFee = fee + public func setMaxTransactionFee(_ fee: Hbar) -> Self { + body.transactionFee = UInt64(fee.asTinybar()) return self } @@ -50,7 +50,7 @@ public class TransactionBuilder { // If we have a client, set some defaults if they have not already been set if let client = client { if body.transactionFee == 0 { - body.transactionFee = client.maxTransactionFee + setMaxTransactionFee(client.maxTransactionFee) } if !body.hasNodeAccountID { diff --git a/Sources/Hedera/TransactionRecord.swift b/Sources/Hedera/TransactionRecord.swift index 713b447a..60f242db 100644 --- a/Sources/Hedera/TransactionRecord.swift +++ b/Sources/Hedera/TransactionRecord.swift @@ -4,7 +4,7 @@ import Foundation public struct TransactionRecord { public let transactionId: TransactionId public let transactionHash: Bytes - public let transactionFee: UInt64 + public let transactionFee: Hbar public let consensusTimestamp: Date? public let transactionMemo: String? public let receipt: TransactionReceipt @@ -18,7 +18,7 @@ public struct TransactionRecord { transactionId = TransactionId(proto.transactionID)! transactionHash = Bytes(proto.transactionHash) - transactionFee = UInt64(proto.transactionFee) + transactionFee = Hbar.fromTinybar(amount: Int64(proto.transactionFee)) consensusTimestamp = proto.hasConsensusTimestamp ? Date(proto.consensusTimestamp): nil transactionMemo = proto.memo.isEmpty ? nil : proto.memo receipt = TransactionReceipt(proto.receipt) @@ -29,28 +29,10 @@ public struct TransactionRecord { public struct Transfer { public let accountId: AccountId - public let amount: UInt64 + public let amount: Hbar init(_ proto: Proto_AccountAmount) { accountId = AccountId(proto.accountID) - amount = UInt64(proto.amount) + amount = Hbar.fromTinybar(amount: proto.amount) } } - -// public enum ContractResultType { -// case call(FunctionResult) -// case create(FunctionResult) - -// init?(_ body: Proto_TransactionRecord.OneOf_Body?) { -// if let body = body { -// switch body { -// case .contractCallResult(let result): -// self = ContractResultType.call(FunctionResult(result)) -// case .contractCreateResult(let result): -// self = ContractResultType.create(FunctionResult(result)) -// } -// } else { -// return nil -// } -// } -// } diff --git a/Sources/Hedera/account/AccountBalanceQuery.swift b/Sources/Hedera/account/AccountBalanceQuery.swift index 53659197..5eb4ce0e 100644 --- a/Sources/Hedera/account/AccountBalanceQuery.swift +++ b/Sources/Hedera/account/AccountBalanceQuery.swift @@ -1,4 +1,4 @@ -public class AccountBalanceQuery: QueryBuilder { +public class AccountBalanceQuery: QueryBuilder { public override init() { super.init() @@ -15,11 +15,11 @@ public class AccountBalanceQuery: QueryBuilder { callback(&body.cryptogetAccountBalance.header) } - override func mapResponse(_ response: Proto_Response) -> UInt64 { + override func mapResponse(_ response: Proto_Response) -> Hbar { guard case .cryptogetAccountBalance(let response) = response.response else { fatalError("unreachable: response is not cryptogetAccountBalance") } - return response.balance + return Hbar.fromTinybar(amount: Int64(response.balance)) } } diff --git a/Sources/Hedera/account/AccountCreateTransaction.swift b/Sources/Hedera/account/AccountCreateTransaction.swift index caf4f855..47551523 100644 --- a/Sources/Hedera/account/AccountCreateTransaction.swift +++ b/Sources/Hedera/account/AccountCreateTransaction.swift @@ -3,17 +3,16 @@ import Foundation public final class AccountCreateTransaction: TransactionBuilder { public override init() { super.init() + body.cryptoCreateAccount = Proto_CryptoCreateTransactionBody() - var inner = Proto_CryptoCreateTransactionBody() // Required fixed autorenew duration (roughly 1/4 year) - inner.autoRenewPeriod = TimeInterval(7_890_000).toProto() + setAutoRenewPeriod(TimeInterval(7_890_000)) // Default to maximum values for record thresholds. Without this, records // would be auto-created whenever a send or receive transaction takes place // for this new account. This should be an explicit ask. - inner.sendRecordThreshold = UInt64(Int64.max) - inner.receiveRecordThreshold = UInt64(Int64.max) + setSendRecordThreshold(Hbar.MAX) + setReceiveRecordThreshold(Hbar.MAX) - body.cryptoCreateAccount = inner } @discardableResult @@ -31,22 +30,22 @@ public final class AccountCreateTransaction: TransactionBuilder { } @discardableResult - public func setInitialBalance(_ balance: UInt64) -> Self { - body.cryptoCreateAccount.initialBalance = balance + public func setInitialBalance(_ balance: Hbar) -> Self { + body.cryptoCreateAccount.initialBalance = UInt64(balance.asTinybar()) return self } @discardableResult - public func setReceiveRecordThreshold(_ threshold: UInt64) -> Self { - body.cryptoCreateAccount.receiveRecordThreshold = threshold + public func setReceiveRecordThreshold(_ threshold: Hbar) -> Self { + body.cryptoCreateAccount.receiveRecordThreshold = UInt64(threshold.asTinybar()) return self } @discardableResult - public func setSendRecordThreshold(_ threshold: UInt64) -> Self { - body.cryptoCreateAccount.sendRecordThreshold = threshold + public func setSendRecordThreshold(_ threshold: Hbar) -> Self { + body.cryptoCreateAccount.sendRecordThreshold = UInt64(threshold.asTinybar()) return self } diff --git a/Sources/Hedera/account/AccountInfo.swift b/Sources/Hedera/account/AccountInfo.swift index cfd43c53..aa7592e9 100644 --- a/Sources/Hedera/account/AccountInfo.swift +++ b/Sources/Hedera/account/AccountInfo.swift @@ -5,11 +5,11 @@ public struct AccountInfo { public let contractAccountId: String? public let isDeleted: Bool public let proxyAccountId: AccountId? - public let proxyReceived: UInt64 + public let proxyReceived: Hbar public let key: PublicKey - public let balance: UInt64 - public let generateSendRecordThreshold: UInt64 - public let generateReceiveRecordThreshold: UInt64 + public let balance: Hbar + public let generateSendRecordThreshold: Hbar + public let generateReceiveRecordThreshold: Hbar public let isReceiverSigRequired: Bool public let expirationTime: Date public let autoRenewPeriod: TimeInterval @@ -26,11 +26,11 @@ public struct AccountInfo { contractAccountId = accountInfo.contractAccountID.isEmpty ? nil : accountInfo.contractAccountID isDeleted = accountInfo.deleted self.proxyAccountId = proxyAccountId - proxyReceived = UInt64(accountInfo.proxyReceived) + proxyReceived = Hbar.fromTinybar(amount: accountInfo.proxyReceived) key = PublicKey.fromProto(accountInfo.key)! - balance = accountInfo.balance - generateSendRecordThreshold = accountInfo.generateSendRecordThreshold - generateReceiveRecordThreshold = accountInfo.generateReceiveRecordThreshold + balance = Hbar.fromTinybar(amount: Int64(accountInfo.balance)) + generateSendRecordThreshold = Hbar.fromTinybar(amount: Int64(accountInfo.generateSendRecordThreshold)) + generateReceiveRecordThreshold = Hbar.fromTinybar(amount: Int64(accountInfo.generateReceiveRecordThreshold)) isReceiverSigRequired = accountInfo.receiverSigRequired expirationTime = Date(accountInfo.expirationTime) autoRenewPeriod = TimeInterval(accountInfo.autoRenewPeriod)! diff --git a/Sources/Hedera/account/AccountInfoQuery.swift b/Sources/Hedera/account/AccountInfoQuery.swift index b9c6b73a..696e48e3 100644 --- a/Sources/Hedera/account/AccountInfoQuery.swift +++ b/Sources/Hedera/account/AccountInfoQuery.swift @@ -1,3 +1,5 @@ +import NIO + public class AccountInfoQuery: QueryBuilder { public override init() { super.init() @@ -5,6 +7,12 @@ public class AccountInfoQuery: QueryBuilder { body.cryptoGetInfo = Proto_CryptoGetInfoQuery() } + override func getCost(client: Client, node: Node) -> EventLoopFuture { + super.getCost(client: client, node: node).map { cost in + return max(cost, Hbar.fromTinybar(amount: 25)) + } + } + public func setAccountId(_ id: AccountId) -> Self { body.cryptoGetInfo.accountID = id.toProto() diff --git a/Sources/Hedera/account/AccountUpdateTransaction.swift b/Sources/Hedera/account/AccountUpdateTransaction.swift index 6026db64..25daf6fe 100644 --- a/Sources/Hedera/account/AccountUpdateTransaction.swift +++ b/Sources/Hedera/account/AccountUpdateTransaction.swift @@ -26,14 +26,14 @@ public final class AccountUpdateTransaction: TransactionBuilder { } @discardableResult - public func setReceiveRecordThreshold(_ threshold: UInt64) -> Self { - body.cryptoUpdateAccount.receiveRecordThresholdWrapper = Google_Protobuf_UInt64Value(threshold) + public func setReceiveRecordThreshold(_ threshold: Hbar) -> Self { + body.cryptoUpdateAccount.receiveRecordThresholdWrapper = Google_Protobuf_UInt64Value(UInt64(threshold.asTinybar())) return self } @discardableResult - public func setSendRecordThreshold(_ threshold: UInt64) -> Self { - body.cryptoUpdateAccount.sendRecordThresholdWrapper = Google_Protobuf_UInt64Value(threshold) + public func setSendRecordThreshold(_ threshold: Hbar) -> Self { + body.cryptoUpdateAccount.sendRecordThresholdWrapper = Google_Protobuf_UInt64Value(UInt64(threshold.asTinybar())) return self } diff --git a/Sources/Hedera/account/CryptoTransferTransaction.swift b/Sources/Hedera/account/CryptoTransferTransaction.swift index 427ff17d..9a4f0875 100644 --- a/Sources/Hedera/account/CryptoTransferTransaction.swift +++ b/Sources/Hedera/account/CryptoTransferTransaction.swift @@ -9,20 +9,22 @@ public final class CryptoTransferTransaction: TransactionBuilder { } @discardableResult - public func addSender(_ sender: AccountId, amount: UInt64) -> Self { - addTransfer(account: sender, amount: -Int64(amount)) + public func addSender(_ sender: AccountId, amount: Hbar) -> Self { + guard amount > Hbar.ZERO else { fatalError("amount must be nonnegative")} + return addTransfer(account: sender, amount: Hbar.fromTinybar(amount: -amount.asTinybar())) } @discardableResult - public func addRecipient(_ recipient: AccountId, amount: UInt64) -> Self { - addTransfer(account: recipient, amount: Int64(amount)) + public func addRecipient(_ recipient: AccountId, amount: Hbar) -> Self { + guard amount > Hbar.ZERO else { fatalError("amount must be nonnegative")} + return addTransfer(account: recipient, amount: amount) } @discardableResult - public func addTransfer(account: AccountId, amount: Int64) -> Self { + public func addTransfer(account: AccountId, amount: Hbar) -> Self { var accountAmount = Proto_AccountAmount() accountAmount.accountID = account.toProto() - accountAmount.amount = amount + accountAmount.amount = amount.asTinybar() body.cryptoTransfer.transfers.accountAmounts.append(accountAmount) diff --git a/Sources/Hedera/contract/ContractCreateTransaction.swift b/Sources/Hedera/contract/ContractCreateTransaction.swift index 161c31f9..a8f17591 100644 --- a/Sources/Hedera/contract/ContractCreateTransaction.swift +++ b/Sources/Hedera/contract/ContractCreateTransaction.swift @@ -41,11 +41,12 @@ public class ContractCreateTransaction: TransactionBuilder { /// Set the initial balance of a contract /// - /// Although the type of `balance` is UInt64, the valid range is [0, 2^63-1] + /// Initial balance must be nonnegative. /// The contract will take ownership of the initial balance @discardableResult - public func setInitialBalance(_ balance: UInt64) -> Self { - body.contractCreateInstance.initialBalance = Int64(balance) + public func setInitialBalance(_ balance: Hbar) -> Self { + guard balance > Hbar.ZERO else { fatalError("initial balance must be nonnegative") } + body.contractCreateInstance.initialBalance = balance.asTinybar() return self } diff --git a/Sources/Hedera/contract/ContractExecuteTransaction.swift b/Sources/Hedera/contract/ContractExecuteTransaction.swift index 01aba7fe..d16f6c98 100644 --- a/Sources/Hedera/contract/ContractExecuteTransaction.swift +++ b/Sources/Hedera/contract/ContractExecuteTransaction.swift @@ -13,8 +13,10 @@ public class ContractExecuteTransaction: TransactionBuilder { /// /// The function must be payable to use this method @discardableResult - public func setPayableAmount(_ amount: UInt64) -> Self { - body.contractCall.amount = Int64(amount) + public func setPayableAmount(_ amount: Hbar) -> Self { + guard amount > Hbar.ZERO else { fatalError("payable amount must be nonnegative") } + + body.contractCall.amount = amount.asTinybar() return self } diff --git a/Sources/Hedera/contract/ContractInfoQuery.swift b/Sources/Hedera/contract/ContractInfoQuery.swift index 6e46cce9..5975c6a6 100644 --- a/Sources/Hedera/contract/ContractInfoQuery.swift +++ b/Sources/Hedera/contract/ContractInfoQuery.swift @@ -1,5 +1,4 @@ -import SwiftProtobuf -import Foundation +import NIO public class ContractInfoQuery: QueryBuilder { public override init() { @@ -8,6 +7,12 @@ public class ContractInfoQuery: QueryBuilder { body.contractGetInfo = Proto_ContractGetInfoQuery() } + override func getCost(client: Client, node: Node) -> EventLoopFuture { + super.getCost(client: client, node: node).map { cost in + return max(cost, Hbar.fromTinybar(amount: 25)) + } + } + public func setContractId(_ id: ContractId) -> Self { body.contractGetInfo.contractID = id.toProto() diff --git a/Sources/Hedera/file/FileInfoQuery.swift b/Sources/Hedera/file/FileInfoQuery.swift index c0613121..f47bc401 100644 --- a/Sources/Hedera/file/FileInfoQuery.swift +++ b/Sources/Hedera/file/FileInfoQuery.swift @@ -1,3 +1,5 @@ +import NIO + public class FileInfoQuery: QueryBuilder { public override init() { super.init() @@ -5,6 +7,12 @@ public class FileInfoQuery: QueryBuilder { body.fileGetInfo = Proto_FileGetInfoQuery() } + override func getCost(client: Client, node: Node) -> EventLoopFuture { + super.getCost(client: client, node: node).map { cost in + return max(cost, Hbar.fromTinybar(amount: 25)) + } + } + public func setFileId(_ id: FileId) -> Self { body.fileGetInfo.fileID = id.toProto()