Files
raspberry/iOS/Wallet/Sources/Swap/Controller/SwapControllerInvestment.swift

662 lines
30 KiB
Swift

//
// SwapControllerInvestment.swift
// Wallet
//
// Created by Saveliy Stavitsky on 3/25/21.
// Copyright © 2021 AM. All rights reserved.
//
import UIKit
// swiftlint:disable:next type_body_length
final class SwapControllerInvestment: UIViewController {
let service = Swap.Service.Investment()
@IBOutlet private weak var scrollView: UIScrollView!
@IBOutlet private weak var tokenGiveView: CommonViewCard!
@IBOutlet private weak var tokenGetView: CommonViewCard!
@IBOutlet private weak var conversionRateStackView: UIStackView!
@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 newPoolWarning: UIView!
@IBOutlet private weak var addRemoveLiquidityStackView: UIStackView!
@IBOutlet private weak var liquidityView: CommonViewCard!
@IBOutlet private weak var segCtrl: UISegmentedControl!
@IBOutlet private weak var conversionFieldsStackView: UIStackView!
@IBOutlet private weak var amount1TextField: CommonTextField!
@IBOutlet private weak var amount2TextField: CommonTextField!
@IBOutlet private weak var minimumTextField: CommonTextField!
@IBOutlet private weak var countStackView: UIStackView!
@IBOutlet private weak var createPoolStackView: UIStackView!
@IBOutlet private weak var removeYouGetStackView: UIStackView!
@IBOutlet private weak var removeYouGetToken1: UILabel!
@IBOutlet private weak var removeYouGetToken2: UILabel!
@IBOutlet private weak var removeYouGetToken1TextField: CommonTextField!
@IBOutlet private weak var removeYouGetToken2TextField: CommonTextField!
@IBOutlet private weak var newPooolFieldsStackView: UIStackView!
@IBOutlet private weak var newAmount1TextField: CommonTextField!
@IBOutlet private weak var newAmount2TextField: CommonTextField!
@IBOutlet private weak var newExchangeRateStackView: UIStackView!
@IBOutlet private weak var newExchangeRate: UILabel!
@IBOutlet private weak var newBackwardExchangeRate: UILabel!
@IBOutlet var swapButton: CommonButtonAction!
var startAction: SwapActionType = .add
override func viewDidLoad() {
super.viewDidLoad()
title = L10n.Swap.Investment.title
navigationItem.leftBarButtonItem = .pop(self)
tabBarItem.title = L10n.Swap.Main.TabBar.title
tokenGiveView.action = .cards(collection: nil)
tokenGetView.action = .cards(collection: nil)
liquidityView.isEnabled = false
segCtrl.setTitle(L10n.Swap.Investment.PoolToken.addTitle, forSegmentAt: 0)
segCtrl.setTitle(L10n.Swap.Investment.PoolToken.removeTitle, forSegmentAt: 1)
segCtrl.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
removeYouGetToken1.isHidden = true
removeYouGetToken2.isHidden = true
for textField in [amount1TextField, amount2TextField, minimumTextField, newAmount1TextField, newAmount2TextField, removeYouGetToken1TextField, removeYouGetToken2TextField] {
textField?.delegate = self
textField?.keyboardType = .decimalPad
}
minimumTextField.precision = 0
swapButton.isHidden = true
service.didUpdate = { [weak self] in
self?.setupTokensViews()
}
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()
}
])
self.selectActionType(type: self.startAction)
}
var observers: [AnyObject] = []
deinit { observers.forEach({ Notification.unsubscribe(observer: $0) }) }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Accounts().isLocked = true
service.fetch {
Alert.error($0)
}
if self.service.tokenGive != nil &&
self.service.tokenGet != nil {
self.setupTokensViews()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
Accounts().isLocked = false
}
var selectedReturnAmountIndex: Int? {
didSet {
if selectedReturnAmountIndex != nil {
minimumTextField.resignFirstResponder()
removeYouGetToken1TextField.resignFirstResponder()
removeYouGetToken2TextField.resignFirstResponder()
}
}
}
func setupCountStackView() {
countStackView.arrangedSubviews.forEach({ $0.removeFromSuperview() })
countStackView.addArrangedSubview(
.button(style: selectedReturnAmountIndex != 0 ? .secondary : .primary,
title: "10%", size: .small, action: { [weak self] in
self?.selectedReturnAmountIndex = 0
if let amount = self?.service.yourPoolSupply?.amount {
self?.service.update(minimum: (amount * 0.1).toReadebleString(precisionMax: 0))
}
self?.setupTokensViews()
})
)
countStackView.addArrangedSubview(
.button(style: selectedReturnAmountIndex != 1 ? .secondary : .primary,
title: "25%", size: .small, action: { [weak self] in
self?.selectedReturnAmountIndex = 1
if let amount = self?.service.yourPoolSupply?.amount {
self?.service.update(minimum: (amount * 0.25).toReadebleString(precisionMax: 0))
}
self?.setupTokensViews()
})
)
countStackView.addArrangedSubview(
.button(style: selectedReturnAmountIndex != 2 ? .secondary : .primary,
title: "50%", size: .small, action: { [weak self] in
self?.selectedReturnAmountIndex = 2
if let amount = self?.service.yourPoolSupply?.amount {
self?.service.update(minimum: (amount * 0.5).toReadebleString(precisionMax: 0))
}
self?.setupTokensViews()
})
)
countStackView.addArrangedSubview(
.button(style: selectedReturnAmountIndex != 3 ? .secondary : .primary,
title: "100%", size: .small, action: { [weak self] in
self?.selectedReturnAmountIndex = 3
if let amount = self?.service.yourPoolSupply?.amount {
self?.service.update(minimum: (amount * 1.0).toReadebleString(precisionMax: 0))
}
self?.setupTokensViews()
})
)
}
// swiftlint:disable:next function_body_length
func setupTokensViews() {
self.tokenGiveView.action = self.setupTokenCard(isGet: false)
self.tokenGetView.action = self.setupTokenCard(isGet: true)
conversionRateStackView.isHidden = service.tokenGive == nil || service.tokenGet == nil || service.pool == nil
addRemoveLiquidityStackView.isHidden = service.tokenGive == nil || service.tokenGet == nil || service.pool == nil
newPoolWarning.isHidden = service.tokenGive == nil || service.tokenGet == nil || service.pool != nil
createPoolStackView.isHidden = service.tokenGive == nil || service.tokenGet == nil || service.pool != nil
newExchangeRateStackView.isHidden = service.tokenGive == nil || service.tokenGet == nil || service.pool != nil
conversionFieldsStackView.isHidden = segCtrl.selectedSegmentIndex == 1
minimumTextField.isHidden = segCtrl.selectedSegmentIndex == 0
removeYouGetStackView.isHidden = segCtrl.selectedSegmentIndex == 0
swapButton.isHidden = true
countStackView.superview?.isHidden = true
guard let tokenGive = service.tokenGive,
let tokenGet = service.tokenGet else {
return
}
removeYouGetToken1TextField.lzPlaceholder = tokenGive.symbol
removeYouGetToken1TextField.lzTitle = tokenGive.symbol
removeYouGetToken2TextField.lzPlaceholder = tokenGet.symbol
removeYouGetToken2TextField.lzTitle = tokenGet.symbol
setupCountStackView()
let giveImg = UIImageView(image: UIImage.from(token: tokenGive))
giveImg.addHeightWidthConstraints(height: 24, width: 24)
newAmount1TextField.accessoryView = giveImg
newAmount1TextField.value = service.newAmountSend
newAmount1TextField.error = service.newAmountSendError
let getImg = UIImageView(image: UIImage.from(token: tokenGet))
getImg.addHeightWidthConstraints(height: 24, width: 24)
newAmount2TextField.accessoryView = getImg
newAmount2TextField.value = service.newAmountReceive
newAmount2TextField.error = service.newAmountReceiveError
swapButton.isHidden = false
if let newAmountSend = service.newAmountSend.toOptionalDecimal(),
let newAmountReceive = service.newAmountReceive.toOptionalDecimal() {
newExchangeRateStackView.isHidden = false
newExchangeRate.lzText = "\(Decimal(1).toString(precision: tokenGive)) = \((newAmountReceive / newAmountSend).toString(precision: tokenGet))"
newBackwardExchangeRate.lzText = "\(Decimal(1).toString(precision: tokenGet)) = \((newAmountSend / newAmountReceive).toString(precision: tokenGive))"
} else {
newExchangeRateStackView.isHidden = true
}
guard let pool = service.pool else {
swapButton.lzTitle = L10n.Swap.Investment.AddPool.buttonTitle
swapButton.isEnabled = !createPoolStackView.isHidden
&& !newAmount1TextField.value.isEmpty
&& !newAmount2TextField.value.isEmpty
&& service.newAmountSend.toDecimal() > 0
&& service.newAmountReceive.toDecimal() > 0
&& service.newAmountSendError == nil
&& service.newAmountReceiveError == nil
return
}
forwardConversionRate.lzText = "\(Decimal(1).toString(precision: tokenGive)) ≈ \(pool.forwardExchangeRate.toString(precision: tokenGet))"
backwardConversionRate.lzText = "\(Decimal(1).toString(precision: tokenGet)) ≈ \(pool.backwardExchangeRate.toString(precision: tokenGive))"
poolSize.lzText = "\(pool.token1?.amount.toString(precision: tokenGive) ?? "") / \(pool.token2?.amount.toString(precision: tokenGet) ?? "")"
if let supplyTokens = service.poolSupply {
poolLiquidity.lzText = "\(supplyTokens.amount.toString(precision: supplyTokens))"
}
liquidityView.action = .select(
icon: UIImage(),
kind: .cards,
title: L10n.Common.Card.Token.title,
empty: .cardsTokensEmpty(),
collection: (service.yourPoolSupply != nil ? [service.yourPoolSupply!] : [])
.map({ $0.toMenu() }),
selected: service.yourPoolSupply?.toMenu(),
completion: { _ in }
)
let giveImage = UIImageView(image: UIImage.from(token: tokenGive))
giveImage.addHeightWidthConstraints(height: 24, width: 24)
amount1TextField.accessoryView = giveImage
amount1TextField.value = service.amountSend
amount1TextField.error = service.amountSendError
let getImage = UIImageView(image: UIImage.from(token: tokenGet))
getImage.addHeightWidthConstraints(height: 24, width: 24)
amount2TextField.accessoryView = getImage
amount2TextField.value = service.amountReceive
amount2TextField.error = service.amountReceiveError
let lImage = UIImageView(image: Asset.tokenSwap.image)
lImage.addHeightWidthConstraints(height: 24, width: 24)
minimumTextField.accessoryView = lImage
minimumTextField.value = service.amountMinimum
minimumTextField.error = service.amountMinimumError
if let minAmount = service.amountMinimum.toOptionalDecimal(),
let poolSupply = service.poolSupply?.amount,
let token1 = pool.token1,
let token2 = pool.token2,
segCtrl.selectedSegmentIndex == 1 {
// removeYouGetStackView.isHidden = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: {
let bottomOffset = CGPoint(x: 0, y: self.scrollView.contentSize.height - self.scrollView.bounds.height + self.scrollView.contentInset.bottom)
self.scrollView.setContentOffset(bottomOffset, animated: true)
})
removeYouGetToken1.lzText = "≈ \((token1.amount * minAmount / poolSupply).toString(precision: token1))"
removeYouGetToken2.lzText = "≈ \((token2.amount * minAmount / poolSupply).toString(precision: token2))"
if !removeYouGetToken1TextField.isFirstResponder {
var amount = token1.amount * minAmount / poolSupply
if token1.isCash { amount = amount.receive(precision: token1.precision) }
if amount <= 0 { amount = 0 }
removeYouGetToken1TextField.value = "≈\(amount.toReadebleString(precisionMax: token1.precision))"
if minAmount == 0 {
removeYouGetToken1TextField.value = "≈\(Decimal(0).toReadebleString(precisionMax: token1.precision))"
}
}
if !removeYouGetToken2TextField.isFirstResponder {
var amount = token2.amount * minAmount / poolSupply
if token2.isCash { amount = amount.receive(precision: token2.precision) }
if amount <= 0 { amount = 0 }
removeYouGetToken2TextField.value = "≈\(amount.toReadebleString(precisionMax: token2.precision))"
if minAmount == 0 {
removeYouGetToken2TextField.value = "≈\(Decimal(0).toReadebleString(precisionMax: token2.precision))"
}
}
} else {
// removeYouGetStackView.isHidden = true
removeYouGetToken1TextField.value = "≈"
removeYouGetToken2TextField.value = "≈"
}
if service.pool == nil {
swapButton.lzTitle = L10n.Swap.Investment.AddPool.buttonTitle
swapButton.isEnabled = !createPoolStackView.isHidden
&& !newAmount1TextField.value.isEmpty
&& !newAmount2TextField.value.isEmpty
&& service.newAmountSend.toDecimal() > 0
&& service.newAmountReceive.toDecimal() > 0
&& service.newAmountSendError == nil
&& service.newAmountReceiveError == nil
} else if !conversionFieldsStackView.isHidden {
swapButton.lzTitle = L10n.Swap.Investment.PoolToken.addButtonTitle
swapButton.isEnabled = !conversionFieldsStackView.isHidden
&& !amount1TextField.value.isEmpty
&& !amount2TextField.value.isEmpty
&& service.amountSend.toDecimal() > 0
&& service.amountReceive.toDecimal() > 0
&& service.amountSendError == nil
&& service.amountReceiveError == nil
} else if !minimumTextField.isHidden {
swapButton.lzTitle = L10n.Swap.Investment.PoolToken.removeButtonTitle
countStackView.superview?.isHidden = false
swapButton.isEnabled = !minimumTextField.isHidden
&& !minimumTextField.value.isEmpty
&& service.amountMinimumError == nil
&& service.amountMinimum.toDecimal() > 0
}
}
private func setupTokenCard(isGet: Bool) -> CommonMenuAction {
let excludedToken = isGet ? self.service.tokenGive : self.service.tokenGet
return .cards(tokens: self.service.swappableBalances.filter({$0 != excludedToken}), selected: isGet ? self.service.tokenGet : self.service.tokenGive, { [weak self] in
guard let self else { return }
isGet ? (self.service.tokenGet = self.service.swappableBalances.object(menu: $0)) : (self.service.tokenGive = self.service.swappableBalances.object(menu: $0))
self.amount1TextField.precision = self.service.swappableBalances.object(menu: $0)?.precision
self.newAmount1TextField.precision = self.service.swappableBalances.object(menu: $0)?.precision
self.setupTokensViews()
})
}
@IBAction private func onChange(_: AnyObject?) {
self.setupTokensViews()
}
@IBAction func swapPressed(_ sender: Any) {
view.endEditing(true)
guard let tokenGive = service.tokenGive,
let tokenGet = service.tokenGet else {
return
}
if service.pool == nil {
let views: [UIView] = [
.label(
text: L10n.Swap.Investment.CreateConfirmation.description
.attributed(style: .regular, size: 14, color: Asset.textCoal.color),
numberOfLines: 0
),
.field(
title: L10n.Swap.Investment.CreateConfirmation.give,
text: service.newAmountSend.toDecimal().toString(max: tokenGive)
+ "\n" + service.newAmountReceive.toDecimal().toString(max: tokenGet)
)
]
Popup.show(title: L10n.Common.Title.confirmation, views: views, submit: L10n.Common.Button.confirm, in: self) { ctrl in
AccountViewAuthorize.showGetPrivateKey(in: self) {
Loader.show(in: ctrl)
self.service.submitCreate(privateKey: $0) { (trxId, lqtoken, error) in
ctrl.dismiss(animated: true)
Alert.notify(error)
let views: [UIView] =
[
.field(
title: L10n.Swap.Investment.Success.debited,
text: (self.service.newAmountSend.toOptionalDecimal()?.toString(max: tokenGive) ?? "")
+ "\n" + (self.service.newAmountReceive.toOptionalDecimal()?.toString(max: tokenGet) ?? "")
),
.field(
title: L10n.Swap.Investment.Success.liquidityGet,
text: lqtoken
)
]
trxId.flatMap { self.showCompletion(transactionId: $0, views: views) }
}
}
}
} else if segCtrl.selectedSegmentIndex == 0 && service.pool != nil {
let views: [UIView] = [
.label(
text: L10n.Swap.Investment.AddConfirmation.description
.attributed(style: .regular, size: 14, color: Asset.textCoal.color),
numberOfLines: 0
),
.field(
title: L10n.Swap.Investment.AddConfirmation.give,
text: service.amountSend.toDecimal().toString(max: tokenGive)
+ "\n" + service.amountReceive.toDecimal().toString(max: tokenGet)
)
]
Popup.show(title: L10n.Common.Title.confirmation,
views: views,
submit: L10n.Common.Button.confirm,
in: self) { ctrl in
AccountViewAuthorize.showGetPrivateKey(in: self) {
Loader.show(in: ctrl)
let amountSend = self.service.amountSend.toOptionalDecimal()?.toString(max: tokenGive)
let amountReceive = self.service.amountReceive.toOptionalDecimal()?.toString(max: tokenGet)
self.service.submitAdd(privateKey: $0) { (trxId, lqtoken, error) in
ctrl.dismiss(animated: true)
Alert.notify(error)
let views: [UIView] =
[
.field(
title: L10n.Swap.Investment.Success.debited,
text: (amountSend ?? "") + "\n" + (amountReceive ?? "")
),
.field(
title: L10n.Swap.Investment.Success.liquidityGet,
text: lqtoken
)
]
trxId.flatMap { self.showCompletion(transactionId: $0, views: views) }
}
}
}
} else if segCtrl.selectedSegmentIndex == 1 && service.pool != nil {
var views: [UIView] = [
.label(
text: L10n.Swap.Investment.RemoveConfirmation.description
.attributed(style: .regular, size: 14, color: Asset.textCoal.color),
numberOfLines: 0
)
]
if let poolSupply = service.poolSupply {
views.append(
.field(
title: L10n.Swap.Investment.RemoveConfirmation.give,
text: service.amountMinimum.toDecimal().toString(max: poolSupply)
)
)
}
if let minAmount = service.amountMinimum.toOptionalDecimal(),
let poolSupply = service.poolSupply?.amount,
let token1 = service.pool?.token1,
let token2 = service.pool?.token2 {
views.append(
.field(
title: L10n.Swap.Investment.RemoveConfirmation.get,
text: ("\(self.removeYouGetToken1TextField.value) \(token1.symbol)"
+ "\n" + "\(self.removeYouGetToken2TextField.value) \(token2.symbol)")
.replacingOccurrences(of: "≈", with: "≈ ")
)
)
}
Popup.show(title: L10n.Common.Title.confirmation, views: views, submit: L10n.Common.Button.confirm, in: self) { ctrl in
AccountViewAuthorize.showGetPrivateKey(in: self) {
Loader.show(in: ctrl)
self.service.submitRemove(privateKey: $0) { (id, error) in
// Loader.hide(in: ctrl)
ctrl.dismiss(animated: true)
Alert.notify(error)
var views: [UIView] =
[
.field(
title: L10n.Swap.Investment.Success.return,
text: (self.service.amountMinimum.toOptionalDecimal()?.toString(max: self.service.poolSupply) ?? "")
)
]
if let minAmount = self.service.amountMinimum.toOptionalDecimal(),
let poolSupply = self.service.poolSupply?.amount,
let token1 = self.service.pool?.token1,
let token2 = self.service.pool?.token2 {
views.append(
.field(
title: L10n.Swap.Investment.Success.got,
text: ("\(self.removeYouGetToken1TextField.value) \(token1.symbol)"
+ "\n" + "\(self.removeYouGetToken2TextField.value) \(token2.symbol)")
.replacingOccurrences(of: "≈", with: "")
)
)
}
id.flatMap { self.showCompletion(transactionId: $0, views: views) }
}
}
}
}
}
private func showCompletion(transactionId: String, views: [UIView]) {
let views = views +
[
.field(
title: L10n.Swap.Investment.Success.Transaction.id,
text: transactionId,
rightButtonAvailbale: true,
rightButtonImage: Asset.commonCopy.image,
rightButtonAction: {
Alert.copy(transactionId)
}
)
]
Popup.show(title: L10n.Swap.Main.Success.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.clear()
}
private func clear() {
selectedReturnAmountIndex = nil
service.update(send: "")
service.update(receive: "")
service.update(newReceive: "")
service.update(newSend: "")
service.update(minimum: "")
}
func selectActionType(type: SwapActionType) {
switch type {
case .add:
self.segCtrl.selectedSegmentIndex = 0
case .withdraw:
self.segCtrl.selectedSegmentIndex = 1
}
setupTokensViews()
}
}
extension SwapControllerInvestment: CommonTextFieldDelegate {
func textField(_ textField: CommonTextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newString = (textField.value as NSString).replacingCharacters(in: range, with: string)
switch textField {
case removeYouGetToken1TextField:
if newString.contains("≈") && !newString.starts(with: "≈") {
return false
}
if let precision = service.pool?.token1?.precision,
newString.replacingOccurrences(of: "≈", with: "").precision > precision {
return false
}
case removeYouGetToken2TextField:
if newString.contains("≈") && !newString.starts(with: "≈") {
return false
}
if let precision = service.pool?.token2?.precision,
newString.replacingOccurrences(of: "≈", with: "").precision > precision {
return false
}
default:
break
}
return true
}
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)
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)
case minimumTextField:
selectedReturnAmountIndex = nil
let newPosition = textField.textField.endOfDocument
textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition)
service.update(minimum: textField.value)
case newAmount1TextField:
textField.value = textField.value.replacingOccurrences(of: ",", with: ".")
let newPosition = textField.textField.endOfDocument
textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition)
service.update(newSend: textField.value)
case newAmount2TextField:
textField.value = textField.value.replacingOccurrences(of: ",", with: ".")
let newPosition = textField.textField.endOfDocument
textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition)
service.update(newReceive: textField.value)
case removeYouGetToken1TextField:
selectedReturnAmountIndex = nil
textField.value = textField.value.replacingOccurrences(of: ",", with: ".")
let newPosition = textField.textField.endOfDocument
textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition)
if !textField.value.starts(with: "≈") { textField.value = "≈\(textField.value)" }
if let poolSupply = service.poolSupply?.amount,
let token1 = service.pool?.token1,
let token2 = service.pool?.token2 {
let minimum = textField.value.replacingOccurrences(of: "≈", with: "").toDecimal() * poolSupply / token1.amount
service.update(minimum: "\(minimum.roundUp(to: 0).toReadebleString(precisionMax: 0))")
}
case removeYouGetToken2TextField:
selectedReturnAmountIndex = nil
textField.value = textField.value.replacingOccurrences(of: ",", with: ".")
let newPosition = textField.textField.endOfDocument
textField.textField.selectedTextRange = textField.textField.textRange(from: newPosition, to: newPosition)
if !textField.value.starts(with: "≈") { textField.value = "≈\(textField.value)" }
if let poolSupply = service.poolSupply?.amount,
let token1 = service.pool?.token1,
let token2 = service.pool?.token2 {
let minimum = textField.value.replacingOccurrences(of: "≈", with: "").toDecimal() * poolSupply / token2.amount
service.update(minimum: "\(minimum.roundUp(to: 0).toReadebleString(precisionMax: 0))")
}
default:
break
}
}
}
extension SwapControllerInvestment {
enum SwapActionType {
case add
case withdraw
}
}