369 lines
16 KiB
Swift
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
|
|
}
|
|
}
|
|
}
|