Files
raspberry/iOS/Wallet/Sources/CCCP/Controller/ExchangeCryptocashViewController/ExchangeCryptocashViewController.swift
T

349 lines
15 KiB
Swift

//
// 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
}
}
}