Files
2023-01-11 16:12:45 +03:00

382 lines
15 KiB
Swift

//
// ExchangeCryptocashViewController.swift
// PayCash
//
// Created by Saveliy Stavitsky on 9/3/22.
// Copyright © 2022 AM. All rights reserved.
//
import UIKit
final class ExchangeCryptocashViewController: UIViewController {
typealias FetchCompletion = () -> Void
private var tokenUSDT = Network.Model.Token(
symbol: "USDT", precision: 4, amount: 100, contract: ""
)
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] {
self.p2pTokenscollection.compactMap { Wallet.Service.Tokens.shared.balances.collection.first($0) }
}
private var selectedToken: Network.Model.Token? {
didSet {
self.amountTextField.isHidden = !self.selectedToken.isExist
let messages = [
L10n.ExchangeCryptocashViewController.Amount.error2,
L10n.ExchangeCryptocashViewController.Amount.error3
]
if messages.contains(where: { $0 == self.amountTextField.error }) {
self.amountTextField.error = nil
}
self.view.endEditing(true)
self.amountTextField.value = ""
self.infoAmountsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
if let selectedToken = self.selectedToken {
self.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)
self.amountTextField.accessoryView = lImage
self.amountTextField.precision = selectedToken.precision
self.amountTextField.becomeFirstResponder()
}
}
}
private var deposits = [Deposit]()
private func calcMLNKViaDeposits(amount: Decimal) -> Decimal {
var tempAmount = amount * tokenUSDT.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 explanationStackView: UIStackView!
@IBOutlet private weak var amountTextField: CommonTextField!
@IBOutlet private weak var infoAmountsStackView: UIStackView!
@IBOutlet private weak var warningView: CommonViewWarning!
@IBOutlet var swapButton: CommonButtonAction!
override func viewDidLoad() {
super.viewDidLoad()
self.title = L10n.ExchangeCryptocashViewController.title
self.navigationItem.leftBarButtonItem = .pop(self)
for textField in [self.amountTextField] {
textField?.delegate = self
textField?.keyboardType = .decimalPad
}
self.amountTextField.lzPlaceholder = L10n.ExchangeCryptocashViewController.Amount.placeholder
self.amountTextField.lzTitle = L10n.ExchangeCryptocashViewController.Amount.title
self.swapButton.isEnabled = false
self.swapButton.isUserInteractionEnabled = false
self.warningView.lzText = L10n.ExchangeCryptocashViewController.warning
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Accounts().isLocked = true
self.fetchData(animated)
}
private func fetchData(_ animated: Bool) {
self.fetchSwap {
self.fetchSwapBack(animated: animated) { [weak self] in
self?.fetchDeposit(animated: animated)
}
}
}
private func fetchSwap(_ completion: @escaping FetchCompletion) {
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] in
if let token = $0.map({ $0.income }).first?.asToken {
self?.tokenUSDT = token
}
completion()
}
}
private func fetchSwapBack(animated: Bool, _ completion: @escaping FetchCompletion) {
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)
}
completion()
}
}
private func fetchDeposit(animated: Bool) {
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] deposits in
self?.deposits = deposits
if deposits.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: (tokenUSDT.amount * (amountTextField.value.toDecimal() / coef)).toString(max: tokenUSDT)
), 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: (tokenUSDT.amount * (amountTextField.value.toDecimal() / coef)).toString(max: tokenUSDT)
)
]
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.tokenUSDT
if !Wallet.Service.Tokens.shared.balances.collection.contains(returnToken) {
actions.append(
(contract: returnToken.contract,
action: .open,
data: [
"owner": Accounts().current?.name ?? "",
"symbol": "\(returnToken.precision),\(returnToken.symbol)",
"ram_payer": Accounts().current?.name ?? ""
])
)
}
actions.append(
(contract: selectedToken.contract,
action: .transfer,
data: [
"from": Accounts().current?.name ?? "",
"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)
delayed(3) { Wallet.Service.Tokens.shared.balances.fetch() }
} 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: (tokenUSDT.amount * (amountTextField.value.toDecimal() / coef)).toString(max: tokenUSDT)
),
.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() > (selectedToken.symbol.uppercased() == "USDCASH" ? 9999 : 0),
amountTextField.value.toDecimal() <= selectedToken.amount {
swapButton.isEnabled = true
swapButton.isUserInteractionEnabled = true
infoAmountsStackView.insertArrangedSubview(
.field(
title: L10n.ExchangeCryptocashViewController.Get.title,
text: (tokenUSDT.amount * (amountTextField.value.toDecimal() / coef)).toString(max: tokenUSDT)
), 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 (selectedToken?.amount ?? 0) < amountTextField.value.toDecimal() {
amountTextField.error = L10n.ExchangeCryptocashViewController.Amount.error3
} else if amountTextField.value.toDecimal() > 0 {
amountTextField.error = amountTextField.lzText
} else {
amountTextField.error = nil
}
}
default:
break
}
}
}