Files
2022-12-26 19:33:09 +03:00

369 lines
16 KiB
Swift

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