// // IssueCryptocashViewController.swift // PayCash // // Created by Saveliy Stavitsky on 9/2/22. // Copyright © 2022 AM. All rights reserved. // import UIKit final class IssueCryptocashViewController: UIViewController { private var token1: Network.Model.Token? 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: 0, contract: ApplicationEnvironment.shared().current.contract(.cash) ) private var swapPool: Swap.Model.Pool? private var swapUSDT: Network.Model.Token? { swapPool?.token1 == token1 ? swapPool?.token1 : swapPool?.token2 } private var swapMLNK: Network.Model.Token? { swapPool?.token1 == token1 ? swapPool?.token2 : swapPool?.token1 } @IBOutlet private weak var forwardConversionRate: UILabel! @IBOutlet private weak var backwardConversionRate: UILabel! @IBOutlet private weak var poolSize: UILabel! @IBOutlet private weak var poolLiquidity: UILabel! @IBOutlet private weak var amount1TextField: CommonTextField! @IBOutlet private weak var amount2TextField: CommonTextField! @IBOutlet private weak var amountOutTextField: CommonTextField! @IBOutlet var swapButton: CommonButtonAction! override func viewDidLoad() { super.viewDidLoad() title = L10n.IssueCryptocashViewController.title navigationItem.leftBarButtonItem = .pop(self) for textField in [amount1TextField, amount2TextField, amountOutTextField] { textField?.delegate = self textField?.keyboardType = .decimalPad } swapButton.isEnabled = false swapButton.isUserInteractionEnabled = false // observers.append(contentsOf: [ // Notification.subscribe(name: .didUpdateBalances) { [weak self] _ in // guard let self = self else { return } // self.service.tokenGive = self.service.swappableBalances.first(where: {$0.symbol == self.service.tokenGive?.symbol}) // self.service.tokenGet = self.service.swappableBalances.first(where: {$0.symbol == self.service.tokenGet?.symbol}) // self.setupTokensViews() // } // ]) } // var observers: [AnyObject] = [] // deinit { observers.forEach({ Notification.unsubscribe(observer: $0) }) } 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: "swap1", scope: ApplicationEnvironment.shared().current.contract(.cash), type: Income.self ) { [weak self] income in self?.token1 = income.map({ $0.income }).first?.asToken if let tokenUSDT = self?.token1 { Network.table.fetch( code: ApplicationEnvironment.shared().current.contract(.swap), table: "pools", scope: ApplicationEnvironment.shared().current.contract(.swap), limit: 1000, type: Swap.Model.Pool.self ) { [weak self] pools in guard let self = self else { return } self.swapPool = pools.first(where: { $0.token1 == tokenUSDT && $0.token2 == self.token2 }) ?? pools.first(where: { $0.token1 == self.token2 && $0.token2 == tokenUSDT }) if let swapUSDT = self.swapUSDT, let swapMLNK = self.swapMLNK { self.token2.amount = (swapMLNK.amount / swapUSDT.amount * tokenUSDT.amount).roundUp(to: 8) self.setupTokensViews() } else { self.navigationController?.popViewController(animated: animated) } } } else { self?.navigationController?.popViewController(animated: animated) } } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) Accounts().isLocked = false } func setupTokensViews() { guard let token1 = token1, let tokenGive = Wallet.Service.Tokens.shared.balances.collection.first(token1), let tokenGet = Wallet.Service.Tokens.shared.balances.collection.first(token2) else { navigationController?.popViewController(animated: true) return } let rateText1 = token1.amount.toReadebleString(precisionMax: token1.precision, symbol: token1.symbol, group: true) let rateText2 = token2.amount.toReadebleString(precisionMax: token2.precision, symbol: token2.symbol, group: true) forwardConversionRate.lzText = "\(rateText1) = \(rateText2)" amount1TextField.lzPlaceholder = L10n.IssueCryptocashViewController.PledgeAmount1.placeholder amount1TextField.lzTitle = L10n.IssueCryptocashViewController.PledgeAmount1.title amount2TextField.lzPlaceholder = L10n.IssueCryptocashViewController.PledgeAmount2.placeholder amount2TextField.lzTitle = L10n.IssueCryptocashViewController.PledgeAmount2.title amountOutTextField.lzPlaceholder = L10n.IssueCryptocashViewController.AmountOut.placeholder amountOutTextField.lzTitle = L10n.IssueCryptocashViewController.AmountOut.placeholder if amount1TextField.value.toDecimal() / token1.amount == (amount1TextField.value.toDecimal() / token1.amount).roundUp(to: 0) { amount1TextField.error = nil } else { if amount1TextField.value.toDecimal() > 0 { amount1TextField.error = L10n.IssueCryptocashViewController.PledgeAmount1.error1 } else { amount1TextField.error = nil } } if amount1TextField.value.toDecimal() > tokenGive.amount { amount1TextField.error = L10n.IssueCryptocashViewController.NoEnoughtBalance.error } if amount2TextField.value.toDecimal() > tokenGet.amount { amount2TextField.error = L10n.IssueCryptocashViewController.NoEnoughtBalance.error } else { amount2TextField.error = nil } [amount2TextField, amountOutTextField].forEach { $0?.isUserInteractionEnabled = false $0?.line1View.isHidden = true $0?.line2View.isHidden = true $0?.isHidden = amount1TextField.value.isEmpty } let giveImage = UIImageView(token: tokenGive) giveImage.addHeightWidthConstraints(height: 24, width: 24) amount1TextField.accessoryView = giveImage amount1TextField.precision = tokenGive.precision // amount1TextField.value = service.amountSend // amount1TextField.error = service.amountSendError let getImage = UIImageView(token: tokenGet) getImage.addHeightWidthConstraints(height: 24, width: 24) amount2TextField.accessoryView = getImage amount2TextField.precision = tokenGet.precision // amount2TextField.value = service.amountReceive // amount2TextField.error = service.amountReceiveError let lImage = UIImageView(token: tokenOut) lImage.addHeightWidthConstraints(height: 24, width: 24) amountOutTextField.accessoryView = lImage amountOutTextField.precision = tokenOut.precision // amountOutTextField.value = service.amountMinimum // amountOutTextField.error = service.amountMinimumError if amountOutTextField.value.toDecimal() / token1.amount == (amountOutTextField.value.toDecimal() / token1.amount).roundUp(to: 0), amount1TextField.value.toDecimal() > 0, amount1TextField.value.toDecimal() <= tokenGive.amount, amount2TextField.value.toDecimal() <= tokenGet.amount { swapButton.isEnabled = true swapButton.isUserInteractionEnabled = true } else { swapButton.isEnabled = false swapButton.isUserInteractionEnabled = false } } @IBAction func swapPressed(_ sender: Any) { view.endEditing(true) guard let token1 = token1, let tokenGive = Wallet.Service.Tokens.shared.balances.collection.first(token1), let tokenGet = Wallet.Service.Tokens.shared.balances.collection.first(token2) else { navigationController?.popViewController(animated: true) return } let views: [UIView] = [ .field( title: L10n.IssueCryptocashViewController.Popup1.title1, text: amount1TextField.value.toDecimal().toString(max: tokenGive) + "\n" + amount2TextField.value.toDecimal().toString(max: tokenGet) ), .field( title: L10n.IssueCryptocashViewController.Popup1.title2, text: amountOutTextField.value.toDecimal().toString(max: tokenOut) ) ] Popup.show(title: L10n.IssueCryptocashViewController.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)]() if !Wallet.Service.Tokens.shared.balances.collection.contains(self.tokenOut) { actions.append( (contract: self.tokenOut.contract, action: .open, data: [ "owner": Accounts().current?.name ?? "", "symbol": "\(self.tokenOut.precision),\(self.tokenOut.symbol)", "ram_payer": Accounts().current?.name ?? "" ]) ) } actions.append( (contract: tokenGive.contract, action: .transfer, data: [ "from": Accounts().current?.name ?? "", "to": ApplicationEnvironment.shared().current.contract(.cash), "quantity": "\(self.amount1TextField.value.toDecimal().toString(precision: tokenGive))", "memo": "" ])) actions.append( (contract: tokenGet.contract, action: .transfer, data: [ "from": Accounts().current?.name ?? "", "to": ApplicationEnvironment.shared().current.contract(.cash), "quantity": "\(self.amount2TextField.value.toDecimal().toString(precision: tokenGet))", "memo": "" ])) Network.Service.Blockchain.execute(actions: actions, privateKeys: [privateKey]) { (result) in ctrl.dismiss(animated: true) if case let .success(trxId) = result { self.showCompletion(transactionId: trxId) delayed(3) { Wallet.Service.Tokens.shared.balances.fetch() } } else { Alert.notify(result.error) } } } } } private func showCompletion(transactionId: String) { guard let token1 = token1, let tokenGive = Wallet.Service.Tokens.shared.balances.collection.first(token1), let tokenGet = Wallet.Service.Tokens.shared.balances.collection.first(token2) else { navigationController?.popViewController(animated: true) return } let views: [UIView] = [ .field( title: L10n.IssueCryptocashViewController.Popup2.title1, text: amount1TextField.value.toDecimal().toString(max: tokenGive) + "\n" + amount2TextField.value.toDecimal().toString(max: tokenGet) ), .field( title: L10n.IssueCryptocashViewController.Popup2.title2, text: amountOutTextField.value.toDecimal().toString(max: tokenOut) ), .field( title: L10n.Wallet.History.Details.id, text: transactionId, rightButtonAvailbale: true, rightButtonImage: Asset.commonCopy.image, rightButtonAction: { Alert.copy(transactionId) } ) ] Popup.show(title: L10n.IssueCryptocashViewController.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 IssueCryptocashViewController: CommonTextFieldDelegate { func textFieldDidChange(_ textField: CommonTextField) { switch textField { case amount1TextField: textField.value = textField.value.replacingOccurrences(of: ",", with: ".") let newPosition = textField.textField.endOfDocument textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition) // service.update(send: textField.value) if let swapUSDT = swapUSDT, let swapMLNK = swapMLNK, let lotUSDTAmount = token1?.amount { amount2TextField.value = ( (swapMLNK.amount / swapUSDT.amount * lotUSDTAmount).roundUp(to: token2.precision) * textField.value.normalized(precision: token1?.precision ?? 0).toDecimal() / lotUSDTAmount ).toString(max: token2.precision, group: false) amountOutTextField.value = textField.value.normalized(precision: tokenOut.precision) } if textField.value.isEmpty { amount2TextField.value = "" } setupTokensViews() case amount2TextField: textField.value = textField.value.replacingOccurrences(of: ",", with: ".") let newPosition = textField.textField.endOfDocument textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition) // service.update(receive: textField.value) if let swapUSDT = swapUSDT, let swapMLNK = swapMLNK { amountOutTextField.value = ( (swapUSDT.amount / swapMLNK.amount * textField.value.normalized(precision: token2.precision).toDecimal()).roundUp(to: tokenOut.precision) ).toString(max: tokenOut.precision, group: false) amount1TextField.value = amountOutTextField.value.normalized(precision: token1?.precision ?? 0) } setupTokensViews() case amountOutTextField: textField.value = textField.value.replacingOccurrences(of: ",", with: ".") let newPosition = textField.textField.endOfDocument textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition) // service.update(minimum: textField.value) if let swapUSDT = swapUSDT, let swapMLNK = swapMLNK, let lotUSDTAmount = token1?.amount { amount2TextField.value = ( (swapMLNK.amount / swapUSDT.amount * lotUSDTAmount).roundUp(to: token2.precision) * textField.value.normalized(precision: tokenOut.precision).toDecimal() / lotUSDTAmount ).toString(max: token2.precision, group: false) amount1TextField.value = textField.value.normalized(precision: token1?.precision ?? 0) } if textField.value.isEmpty { amount2TextField.value = "" } setupTokensViews() default: break } } }