// // ExchangeCryptocashViewController.swift // PayCash // // Created by Saveliy Stavitsky on 9/3/22. // Copyright © 2022 AM. All rights reserved. // import UIKit class ExchangeCryptocashViewController: UIViewController { private var token1 = Network.Model.Token( symbol: "USDT", precision: 4, amount: 100, contract: "" ) private var token2 = Network.Model.Token( symbol: "MLNK", precision: 8, amount: 0, contract: ApplicationEnvironment.shared().current.contract(.swap) ) private var tokenOut = Network.Model.Token( symbol: "USDCASH", precision: 5, amount: 100, contract: ApplicationEnvironment.shared().current.contract(.cash) ) private var p2pTokenscollection: [Network.Model.Token] = [] private var walletP2pTokenscollection: [Network.Model.Token] { p2pTokenscollection.compactMap({ Wallet.Service.Tokens.shared.balances.collection.first($0) }) } private var selectedToken: Network.Model.Token? { didSet { buttonsStackView.isHidden = selectedToken == nil amountTextField.isHidden = selectedToken == nil view.endEditing(true) amountTextField.value = "" infoAmountsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } if let selectedToken = self.selectedToken { amountTextField.lzText = L10n.ExchangeCryptocashViewController.Amount.info + (p2pTokenscollection.first(selectedToken)?.certCoef ?? 0) .toReadebleString(precisionMax: selectedToken.precision, symbol: selectedToken.symbol, group: true) let lImage = UIImageView(token: selectedToken) lImage.addHeightWidthConstraints(height: 24, width: 24) amountTextField.accessoryView = lImage amountTextField.precision = selectedToken.precision } } } private var deposits: [Deposit] = [] private func calcMLNKViaDeposits(amount: Decimal) -> Decimal { var tempAmount = amount * token1.amount var tempMLNK = Decimal(0) for deposit in deposits { if tempAmount <= 0 { break } if deposit.usdt_in.amount.toDecimal() <= tempAmount { tempMLNK += deposit.mlnk_in.amount.toDecimal() tempAmount -= deposit.usdt_in.amount.toDecimal() } else { tempMLNK += tempAmount * (deposit.mlnk_in.amount.toDecimal() / deposit.usdt_in.amount.toDecimal()) tempAmount -= tempAmount } } return tempMLNK } @IBOutlet private weak var tokeGiveView: CommonViewCard! @IBOutlet private weak var buttonsStackView: UIStackView! @IBOutlet private weak var accountTypeView: CommonViewRadioGroup! @IBOutlet private weak var amountTextField: CommonTextField! @IBOutlet private weak var infoAmountsStackView: UIStackView! @IBOutlet var swapButton: CommonButtonAction! override func viewDidLoad() { super.viewDidLoad() title = L10n.ExchangeCryptocashViewController.title navigationItem.leftBarButtonItem = .pop(self) for textField in [amountTextField] { textField?.delegate = self textField?.keyboardType = .decimalPad } amountTextField.lzPlaceholder = L10n.ExchangeCryptocashViewController.Amount.placeholder amountTextField.lzTitle = L10n.ExchangeCryptocashViewController.Amount.title swapButton.isEnabled = false swapButton.isUserInteractionEnabled = false accountTypeView.collection = ["USDT", "MLNK"] accountTypeView.isHorizontal = true } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) Accounts().isLocked = true fetchData(animated) } private func fetchData(_ animated: Bool) { struct Income: Codable { let income: Network.Model.TokenSmall } Network.table.fetch( code: ApplicationEnvironment.shared().current.contract(.cash), table: "swap", scope: ApplicationEnvironment.shared().current.contract(.cash), type: Income.self ) { [weak self] in if let token = $0.map({ $0.income }).first?.asToken { self?.token1 = token } } struct CashToken: Codable { private let cash: String var symbol: String { String(cash.split(separator: " ").last!) } var precision: Int { cash.amount.precision } var coef: Decimal { cash.amount.toDecimal() } func asNetworkToken() -> Network.Model.Token { .init(symbol: symbol, precision: precision, amount: 0, contract: ApplicationEnvironment.shared().current.contract(.cash), certCoef: coef, certName: "") } } Network.table.fetch( code: ApplicationEnvironment.shared().current.contract(.cash), table: "swapback", scope: ApplicationEnvironment.shared().current.contract(.cash), type: CashToken.self) { [weak self] rows in guard let self = self else { return } self.p2pTokenscollection = rows.map({ $0.asNetworkToken() }) if !self.p2pTokenscollection.isEmpty { self.tokeGiveView.action = .cards( tokens: self.walletP2pTokenscollection, selected: self.selectedToken, empty: .menu( image: Asset.commonToken.image.tinted(with: Asset.deepWater.color), title: L10n.ExchangeCryptocashViewController.Cryptocash.placeholder ), title: L10n.ExchangeCryptocashViewController.Cryptocash.placeholder, { self.selectedToken = self.walletP2pTokenscollection.object(menu: $0) } ) } else { self.navigationController?.popViewController(animated: animated) } } Network.table.fetch( code: ApplicationEnvironment.shared().current.contract(.cash), table: "deposits", scope: ApplicationEnvironment.shared().current.contract(.cash), keyType: "i128", indexPosition: "2", type: Deposit.self ) { [weak self] in self?.deposits = $0 if $0.isEmpty { self?.navigationController?.popViewController(animated: animated) } } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) Accounts().isLocked = false } @IBAction private func onAccountType(_ : AnyObject?) { guard let selectedToken = self.selectedToken, let coef = p2pTokenscollection.first(selectedToken)?.certCoef, amountTextField.value.toDecimal() / coef == (amountTextField.value.toDecimal() / coef).roundUp(to: 0), amountTextField.value.toDecimal() > 0 else { return } infoAmountsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } if let coef = p2pTokenscollection.first(selectedToken)?.certCoef { infoAmountsStackView.insertArrangedSubview( .field( title: L10n.ExchangeCryptocashViewController.Get.title, text: accountTypeView.selectedIndex == 0 ? (token1.amount * (amountTextField.value.toDecimal() / coef)).toString(max: token1) : calcMLNKViaDeposits(amount: amountTextField.value.toDecimal() / coef).toString(max: token2) ), at: 0) infoAmountsStackView.insertArrangedSubview( .field( title: L10n.ExchangeCryptocashViewController.Return.title, text: amountTextField.value.toDecimal().toString(max: selectedToken) ), at: 0) } } @IBAction func swapPressed(_ sender: Any) { view.endEditing(true) guard let selectedToken = self.selectedToken, let coef = p2pTokenscollection.first(selectedToken)?.certCoef else { return } let views: [UIView] = [ .field( title: L10n.ExchangeCryptocashViewController.Popup1.title1, text: amountTextField.value.toDecimal().toString(max: selectedToken) ), .field( title: L10n.ExchangeCryptocashViewController.Popup1.title2, text: accountTypeView.selectedIndex == 0 ? (token1.amount * (amountTextField.value.toDecimal() / coef)).toString(max: token1) : calcMLNKViaDeposits(amount: amountTextField.value.toDecimal() / coef).toString(max: token2) ) ] Popup.show(title: L10n.ExchangeCryptocashViewController.Popup1.title, views: views, submit: L10n.Common.Button.confirm, in: self) { ctrl in AccountViewAuthorize.showGetPrivateKey(in: self) { privateKey in Loader.show(in: ctrl) var actions = [(contract: String, action: Network.Model.Blockchain.Action, data: Codable)]() let returnToken = self.accountTypeView.selectedIndex == 0 ? self.token1 : self.token2 if !Wallet.Service.Tokens.shared.balances.collection.contains(returnToken) { actions.append( (contract: returnToken.contract, action: .open, data: [ "owner": Accounts().current?.username ?? "", "symbol": "\(returnToken.precision),\(returnToken.symbol)", "ram_payer": Accounts().current?.username ?? "" ]) ) } actions.append( (contract: selectedToken.contract, action: .transfer, data: [ "from": Accounts().current?.username ?? "", "to": ApplicationEnvironment.shared().current.contract(.cash), "quantity": "\(self.amountTextField.value.toDecimal().toString(precision: selectedToken))", "memo": returnToken.symbol.lowercased() ])) Network.Service.Blockchain.execute(actions: actions, privateKeys: [privateKey]) { (result) in ctrl.dismiss(animated: true) if case let .success(trxId) = result { self.showCompletion(transactionId: trxId) } else { Alert.notify(result.error) } } } } } private func showCompletion(transactionId: String) { guard let selectedToken = self.selectedToken, let coef = p2pTokenscollection.first(selectedToken)?.certCoef else { return } let views: [UIView] = [ .field( title: L10n.ExchangeCryptocashViewController.Popup2.title1, text: amountTextField.value.toDecimal().toString(max: selectedToken) ), .field( title: L10n.ExchangeCryptocashViewController.Popup2.title2, text: accountTypeView.selectedIndex == 0 ? (token1.amount * (amountTextField.value.toDecimal() / coef)).toString(max: token1) : calcMLNKViaDeposits(amount: amountTextField.value.toDecimal() / coef).toString(max: token2) ), .field( title: L10n.Wallet.History.Details.id, text: transactionId, rightButtonAvailbale: true, rightButtonImage: Asset.commonCopy.image, rightButtonAction: { Alert.copy(transactionId) } ) ] Popup.show(title: L10n.ExchangeCryptocashViewController.Popup2.title, views: views, submit: L10n.Common.Button.checkOnBloksIO, submitStyle: .outline, cancel: L10n.Common.Button.done, in: self, { ctrl in guard let checkTransactionUrl = URL(transactionId: transactionId) else { return } UIApplication.shared.open(checkTransactionUrl, options: [:], completionHandler: nil) }, { self.navigationController?.popViewController(animated: true) }) } } extension ExchangeCryptocashViewController: CommonTextFieldDelegate { func textFieldDidChange(_ textField: CommonTextField) { switch textField { case amountTextField: textField.value = textField.value.replacingOccurrences(of: ",", with: ".") let newPosition = textField.textField.endOfDocument textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition) infoAmountsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } if let selectedToken = self.selectedToken, let coef = p2pTokenscollection.first(selectedToken)?.certCoef, amountTextField.value.toDecimal() / coef == (amountTextField.value.toDecimal() / coef).roundUp(to: 0), amountTextField.value.toDecimal() > 0 { swapButton.isEnabled = true swapButton.isUserInteractionEnabled = true infoAmountsStackView.insertArrangedSubview( .field( title: L10n.ExchangeCryptocashViewController.Get.title, text: accountTypeView.selectedIndex == 0 ? (token1.amount * (amountTextField.value.toDecimal() / coef)).toString(max: token1) : calcMLNKViaDeposits(amount: amountTextField.value.toDecimal() / coef).toString(max: token2) ), at: 0) infoAmountsStackView.insertArrangedSubview( .field( title: L10n.ExchangeCryptocashViewController.Return.title, text: amountTextField.value.toDecimal().toString(max: selectedToken) ), at: 0) } else { swapButton.isEnabled = false swapButton.isUserInteractionEnabled = false if amountTextField.value.toDecimal() > 0 { amountTextField.error = amountTextField.lzText } else { amountTextField.error = nil } } default: break } } }