// // NetworkModelToken.swift // Wallet // // Created by Igor on 04.11.2020. // Copyright © 2020 List. All rights reserved. // import UIKit extension Network.Model { struct TokenSmall: Codable { let quantity: String let contract: String var asToken: Token? { if !contract.isEmpty, !quantity.symbol.isEmpty { return Token( symbol: quantity.symbol, precision: quantity.precision, amount: quantity.amount.toDecimal(), contract: contract, certCoef: 0, certName: "", city: nil, country: nil ) } else { return nil } } } struct TokenSmallParsed: Codable { let amount: Decimal let amountDouble: Double let id: String let symbol: String let contract: String let precision: Int var asToken: Token? { if !contract.isEmpty, !symbol.isEmpty { return Token( symbol: symbol, precision: precision, amount: amount, contract: contract, certCoef: 0, certName: "", city: nil, country: nil ) } else { return nil } } } struct Token: Codable { let symbol: String let precision: Int var amount: Decimal let contract: String var country: String? var city: String? var pool: Swap.Model.Pool? // Cash tokens fields var certCoef: Decimal var certName: String init( symbol: String, precision: Int, amount: Decimal, contract: String, certCoef: Decimal = 100, certName: String? = nil, city: String? = nil, country: String? = nil ) { self.symbol = symbol self.precision = precision self.amount = amount self.contract = contract self.certCoef = certCoef self.certName = certName ?? String(symbol.uppercased().dropFirst(2)) self.city = city self.country = country } enum CodingKeys: String, CodingKey { case symbol case precision case amount case contract case currency case decimals } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) if let value = try? values.decodeIfPresent(String.self, forKey: .symbol) { symbol = value precision = try values.decodeIfPresent(Int.self, forKey: .precision) ?? 0 let amountString = (try values.decodeIfPresent(Double.self, forKey: .amount) ?? 0.0).toString(precision: precision) amount = Decimal(string: amountString) ?? 0.0 } else { symbol = try values.decodeIfPresent(String.self, forKey: .currency) ?? "" precision = Int((try? values.decodeIfPresent(String.self, forKey: .decimals)) ?? "0") ?? 0 amount = (try? values.decodeIfPresent(String.self, forKey: .amount))?.toDecimal() ?? 0.0 } contract = try values.decodeIfPresent(String.self, forKey: .contract) ?? "" certCoef = 100 certName = String(symbol.uppercased().dropFirst(2)) } func encode(to encoder: Encoder) throws {} } } extension Network.Model.Token { var swappableContracts: Bool { (!isSwapContract || isMLNK) && checkSafeName() && !isCertificate } var isCashContract: Bool { contract == ApplicationEnvironment.shared().current.contract(.cash) } var isListContract: Bool { contract == ApplicationEnvironment.shared().current.contract(.list) } var isSwapContract: Bool { contract == ApplicationEnvironment.shared().current.contract(.swap) } var isUSDTContract: Bool { contract == ApplicationEnvironment.shared().current.contract(.usdt) } var isOurContract: Bool { isCashContract || isListContract || isSwapContract } var isUSDTName: Bool { symbol.uppercased() == "USDT" } var isUSDT: Bool { isUSDTContract && isUSDTName } var isMLNKName: Bool { symbol.uppercased() == "MLNK" } var isMLNK: Bool { isSwapContract && isMLNKName } var isListName: Bool { symbol.uppercased().hasPrefix("LI") && symbol.count == 7 } var isList: Bool { isListContract && isListName } var isCashName: Bool { symbol.uppercased().hasSuffix("CASH") && symbol.count == 7 } var isCash: Bool { isCashContract && isCashName } var isKLNKName: Bool { symbol.uppercased() == "KLNK" } var isKLNK: Bool { isCashContract && isKLNKName } var isCertificateName: Bool { symbol.uppercased().hasPrefix("G") && !symbol.uppercased().hasSuffix("CASH") && symbol.count == 7 } var isCertificate: Bool { isCashContract && isCertificateName } } extension Network.Model.Token: CustomStringConvertible { var description: String { amount.toString(max: precision, symbol: symbol) } } extension Network.Model.Token { func checkSafeName() -> Bool { let ourNames = ["USDCASH","EURCASH", "UAHCASH","RUBCASH", "GBPCASH","INRCASH", "RMBCASH","JPYCASH", "MLNK", "LIRUMOW","LIRUCEK", "LIRULED","LIUAIEV"] if !self.isOurContract { return !ourNames.contains(self.symbol) } return true } } extension Network.Model.Token { var name: String? { var name: String? if let city = city, let country = country, isListContract { name = "LiST \(country), \(city)" } else if isKLNK { return "Kalinka" } else if isCashContract { switch symbol.uppercased() { case "USDCASH": name = L10n.Wallet.Token.Usdcash.description case "EURCASH": name = L10n.Wallet.Token.Eurcash.description case "UAHCASH": name = L10n.Wallet.Token.Uahcash.description case "RUBCASH": name = L10n.Wallet.Token.Rubcash.description case "GBPCASH": name = L10n.Wallet.Token.Gbpcash.description case "INRCASH": name = L10n.Wallet.Token.Inrcash.description case "RMBCASH": name = L10n.Wallet.Token.Rmbcash.description case "JPYCASH": name = L10n.Wallet.Token.Jpycash.description default: switch symbol.uppercased().dropFirst().first { case "U": name = L10n.Wallet.Token.Cert.description(L10n.Wallet.Token.usdcash, city ?? "") case "E": name = L10n.Wallet.Token.Cert.description(L10n.Wallet.Token.eurcash, city ?? "") case "H": name = L10n.Wallet.Token.Cert.description(L10n.Wallet.Token.uahcash, city ?? "") case "R": name = L10n.Wallet.Token.Cert.description(L10n.Wallet.Token.rubcash, city ?? "") case "G": name = L10n.Wallet.Token.Cert.description(L10n.Wallet.Token.gbpcash, city ?? "") case "I": name = L10n.Wallet.Token.Cert.description(L10n.Wallet.Token.inrcash, city ?? "") case "J": name = L10n.Wallet.Token.Cert.description(L10n.Wallet.Token.rmbcash, city ?? "") case "Y": name = L10n.Wallet.Token.Cert.description(L10n.Wallet.Token.jpycash, city ?? "") default: name = nil } } } else if isMLNK { return "Malinka" } else if let pool = pool { name = "\(pool.token1?.symbol ?? "") - \(pool.token2?.symbol ?? "")" } else { name = contract } return name?.uppercased().replacingOccurrences(of: "LIST", with: "LiST") } } extension Network.Model.Token: CommonMenuMappable { func toMenu() -> Common.Model.Menu { .menu( uuid: symbol + contract, image: .from(token: Network.Model.TokenSmall(quantity: "0 \(symbol)", contract: contract).asToken), imageURLs: [.from(symbol: symbol, contract: contract), .from(symbol: symbol)], title: symbol, text: name, details: amount.toString(max: precision) ) } } extension Network.Model.Token { static let eosioToken = Network.Model.Token(symbol: "EOS", precision: 4, amount: 0, contract: ApplicationEnvironment.shared().current.contract(.eosioToken)) } extension Network.Model.Token: Equatable { static func == (lhs: Network.Model.Token, rhs: Network.Model.Token) -> Bool { lhs.symbol == rhs.symbol && lhs.contract == rhs.contract } } extension Network.Model.Token: Hashable { func hash(into hasher: inout Hasher) { hasher.combine(symbol) hasher.combine(contract) } } extension Array where Element == Network.Model.Token { func first(_ element: Element) -> Element? { if let index = firstIndex(of: element) { return self[index] } return nil } }