Skip to content

Commit

Permalink
fine tuning
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-dydx committed Sep 13, 2024
1 parent d2402f5 commit 2c842f1
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import dydxStateManager
import FloatingPanel
import PlatformRouting
import dydxFormatter
import Combine
import class Abacus.Subaccount

public class dydxVaultDepositWithdrawConfirmationViewBuilder: NSObject, ObjectBuilderProtocol {
public func build<T>() -> T? {
Expand All @@ -29,12 +31,12 @@ private class dydxVaultDepositWithdrawConfirmationViewController: HostingViewCon

override public func arrive(to request: RoutingRequest?, animated: Bool) -> Bool {
let presenter = presenter as? dydxVaultDepositWithdrawConfirmationViewPresenterProtocol
presenter?.viewModel?.amount = request?.params?["amount"] as? Double
presenter?.amount = request?.params?["amount"] as? Double
if request?.path == "/vault/deposit_confirm" {
presenter?.viewModel?.transferType = .deposit
presenter?.transferType = .deposit
return true
} else if request?.path == "/vault/withdraw_confirm" {
presenter?.viewModel?.transferType = .withdraw
presenter?.transferType = .withdraw
return true
} else {
return false
Expand All @@ -44,59 +46,32 @@ private class dydxVaultDepositWithdrawConfirmationViewController: HostingViewCon

private protocol dydxVaultDepositWithdrawConfirmationViewPresenterProtocol: HostedViewPresenterProtocol {
var viewModel: dydxVaultDepositWithdrawConfirmationViewModel? { get }
var transferType: VaultTransferType? { get set }
var amount: Double? { get set }
}

private class dydxVaultDepositWithdrawConfirmationViewPresenter: HostedViewPresenter<dydxVaultDepositWithdrawConfirmationViewModel>, dydxVaultDepositWithdrawConfirmationViewPresenterProtocol {
static let slippageAcknowledgementThreshold = 1.0
static let slippageAcknowledgementThreshold = 0.01

var transferType: VaultTransferType?
var amount: Double?

override init() {
super.init()
self.viewModel = dydxVaultDepositWithdrawConfirmationViewModel(faqUrl: AbacusStateManager.shared.environment?.links?.vaultLearnMore ?? "")

viewModel = dydxVaultDepositWithdrawConfirmationViewModel()
}

override func start() {
super.start()

guard let viewModel = viewModel else { return }

viewModel.slippage = 4.20

viewModel.$transferType
.sink {[weak self] transferType in
switch transferType {
case .deposit:
viewModel.submitState = .enabled
case .withdraw:
viewModel.submitState = .loading
//TO-DO replace fetch slippage and update view model
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
guard let self = self else { return }
let requiresAcknowledgeHighSlippage = transferType == .withdraw && Double.random(in: 0...1.5) > Self.slippageAcknowledgementThreshold // replace random with actual slippage
viewModel.requiresAcknowledgeHighSlippage = requiresAcknowledgeHighSlippage
if requiresAcknowledgeHighSlippage && !viewModel.hasAcknowledgedHighSlippage {
self.viewModel?.submitState = .disabled
} else {
self.viewModel?.submitState = .enabled
}
}
}
}
.store(in: &subscriptions)

// handle slippage toggling
viewModel.$hasAcknowledgedHighSlippage
.sink {[weak self] hasAcknowledged in
guard let viewModel = self?.viewModel, viewModel.requiresAcknowledgeHighSlippage else { return }
switch viewModel.submitState {
case .enabled, .disabled:
viewModel.submitState = hasAcknowledged ? .enabled : .disabled
case .submitting, .loading:
return
}
}
.store(in: &subscriptions)
guard let viewModel else { return }

viewModel.amount = amount
viewModel.faqUrl = AbacusStateManager.shared.environment?.links?.vaultLearnMore ?? ""
viewModel.transferType = transferType

initializeSubmitState()

viewModel.cancelAction = {
Router.shared?.navigate(to: RoutingRequest(path: "/action/dismiss"), animated: true, completion: nil)
Expand All @@ -116,35 +91,93 @@ private class dydxVaultDepositWithdrawConfirmationViewPresenter: HostedViewPrese
}
}
}

// handle slippage toggling
viewModel.$hasAcknowledgedHighSlippage
.sink {[weak self] hasAcknowledged in
self?.update(newHasAcknowledged: hasAcknowledged)
}
.store(in: &subscriptions)

// TODO: replace with real hooks from abacus
update()
AbacusStateManager.shared.state.selectedSubaccount
.sink { [weak self] selectedSubaccount in
self?.update(subaccount: selectedSubaccount)
}
.store(in: &subscriptions)
}

private func initializeSubmitState() {
guard let viewModel, let transferType else { return }
switch transferType {
case .deposit:
viewModel.submitState = .enabled
case .withdraw:
viewModel.submitState = .loading
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
//TO-DO replace fetch actual slippage and update view model
let slippage = Double.random(in: 0...0.02) // replace random with actual slippage
let requiresAcknowledgeHighSlippage = transferType == .withdraw && slippage >= Self.slippageAcknowledgementThreshold
viewModel.requiresAcknowledgeHighSlippage = requiresAcknowledgeHighSlippage
viewModel.slippage = slippage
if requiresAcknowledgeHighSlippage && !viewModel.hasAcknowledgedHighSlippage {
self.viewModel?.submitState = .disabled
} else {
self.viewModel?.submitState = .enabled
}
}
}
}

// TODO: replace with real data from abacus
func update() {
guard let viewModel = viewModel else { return }
let crossFreeCollateralReceiptItem = dydxReceiptChangeItemView(title: DataLocalizer.localize(path: "APP.GENERAL.CROSS_FREE_COLLATERAL"),
value: AmountChangeModel(before: AmountTextModel(amount: 30.01),
after: AmountTextModel(amount: 30.02)))
let yourVaultBalanceReceiptItem = dydxReceiptChangeItemView(title: DataLocalizer.localize(path: "APP.VAULTS.YOUR_VAULT_BALANCE"),
value: AmountChangeModel(before: AmountTextModel(amount: 30.01),
after: AmountTextModel(amount: 30.02)))
let estSlippageReceiptItem = dydxReceiptChangeItemView(title: DataLocalizer.localize(path: "APP.VAULTS.EST_SLIPPAGE"),
value: AmountChangeModel(before: AmountTextModel(amount: 30.01),
after: AmountTextModel(amount: 30.02)))
let expectedAmountReceivedItem = dydxReceiptChangeItemView(title: DataLocalizer.localize(path: "APP.WITHDRAW_MODAL.EXPECTED_AMOUNT_RECEIVED"),
value: AmountChangeModel(before: AmountTextModel(amount: 30.01),
after: AmountTextModel(amount: 30.02)))
let crossMarginUsageItem = dydxReceiptChangeItemView(title: DataLocalizer.localize(path: "APP.GENERAL.CROSS_MARGIN_USAGE"),
value: AmountChangeModel(before: AmountTextModel(amount: 30.01),
after: AmountTextModel(amount: 30.02)))

switch viewModel.transferType {
case .deposit:
viewModel.receiptItems = [crossFreeCollateralReceiptItem, crossMarginUsageItem, yourVaultBalanceReceiptItem]
case .withdraw:
viewModel.receiptItems = [crossFreeCollateralReceiptItem, yourVaultBalanceReceiptItem, estSlippageReceiptItem, expectedAmountReceivedItem]
func update(subaccount: Subaccount?) {
guard let amount,
let transferType,
amount > 0,
// TODO: replace
let curVaultBalance = Optional(420.0),
let curFreeCollateral = subaccount?.freeCollateral?.current?.doubleValue,
let curMarginUsage = subaccount?.marginUsage?.current?.doubleValue
else {
assertionFailure()
return
}

viewModel?.curMarginUsage = curMarginUsage
viewModel?.curFreeCollateral = curFreeCollateral
viewModel?.curVaultBalance = curVaultBalance

switch transferType {
case .deposit:
viewModel?.postVaultBalance = curVaultBalance + amount
viewModel?.postFreeCollateral = curFreeCollateral - amount
viewModel?.postMarginUsage = curMarginUsage - amount
case .withdraw:
viewModel?.postVaultBalance = curVaultBalance - amount
viewModel?.postFreeCollateral = curFreeCollateral + amount
viewModel?.postMarginUsage = curMarginUsage + amount
}
}

private func update(newHasAcknowledged: Bool) {
guard let viewModel, newHasAcknowledged else { return }
switch viewModel.submitState {
case .enabled, .disabled:
viewModel.submitState = newHasAcknowledged ? .enabled : .disabled
case .submitting, .loading:
return
}
}

private func updateSubmitState(slippage: Double?, transferType: VaultTransferType) {
switch transferType {
case .deposit:
viewModel?.submitState = .enabled
case .withdraw:
if let slippage = slippage, viewModel?.requiresAcknowledgeHighSlippage == false || viewModel?.hasAcknowledgedHighSlippage == true {
viewModel?.submitState = .enabled
} else {
viewModel?.submitState = .disabled
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,7 @@ private class dydxVaultViewBuilderPresenter: HostedViewPresenter<dydxVaultViewMo
viewModel = dydxVaultViewModel()
viewModel?.vaultChart = dydxVaultChartViewModel()

let usdcToken = AbacusStateManager.shared.environment?.usdcTokenInfo?.denom
AbacusStateManager.shared.state.accountBalance(of: usdcToken)
.sink {[weak self] usdcBalance in
if usdcBalance ?? 0 > 0 {
self?.viewModel?.depositAction = { Router.shared?.navigate(to: RoutingRequest(path: "/vault/deposit"), animated: true, completion: nil) }
}
}
.store(in: &subscriptions)
// TODO: check if vault balance is > 0 and set up withdraw action
viewModel?.depositAction = { Router.shared?.navigate(to: RoutingRequest(path: "/vault/deposit"), animated: true, completion: nil) }
viewModel?.withdrawAction = {
Router.shared?.navigate(to: RoutingRequest(path: "/vault/withdraw"), animated: true, completion: nil)
}
Expand Down
4 changes: 4 additions & 0 deletions dydx/dydxViews/dydxViews.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
277E914A2B23BB74005CCBCB /* dydxRewardsLearnMoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277E91492B23BB74005CCBCB /* dydxRewardsLearnMoreView.swift */; };
277E918B2B27762F005CCBCB /* dydxRewardsLaunchIncentivesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277E918A2B27762F005CCBCB /* dydxRewardsLaunchIncentivesView.swift */; };
27823D132C77E38C009BCD51 /* dydxVaultDepositWithdrawViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27823D122C77E38C009BCD51 /* dydxVaultDepositWithdrawViewModel.swift */; };
27897DA22C94E71500196F21 /* ReceiptLoadingItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27897DA12C94E71500196F21 /* ReceiptLoadingItemView.swift */; };
278A4DA22B8FA609003898EB /* dydxRateAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 278A4DA12B8FA609003898EB /* dydxRateAppView.swift */; };
27A799B92A66EC2D007C3D04 /* ThemeClassicDark.json in Resources */ = {isa = PBXBuildFile; fileRef = 27A799B82A66EC2D007C3D04 /* ThemeClassicDark.json */; };
27AAA9862ACE34C800AF3C56 /* SwiftMessages+Banner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27AAA9852ACE34C800AF3C56 /* SwiftMessages+Banner.swift */; };
Expand Down Expand Up @@ -581,6 +582,7 @@
277E91492B23BB74005CCBCB /* dydxRewardsLearnMoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxRewardsLearnMoreView.swift; sourceTree = "<group>"; };
277E918A2B27762F005CCBCB /* dydxRewardsLaunchIncentivesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxRewardsLaunchIncentivesView.swift; sourceTree = "<group>"; };
27823D122C77E38C009BCD51 /* dydxVaultDepositWithdrawViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxVaultDepositWithdrawViewModel.swift; sourceTree = "<group>"; };
27897DA12C94E71500196F21 /* ReceiptLoadingItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptLoadingItemView.swift; sourceTree = "<group>"; };
278A4DA12B8FA609003898EB /* dydxRateAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxRateAppView.swift; sourceTree = "<group>"; };
27A799B82A66EC2D007C3D04 /* ThemeClassicDark.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ThemeClassicDark.json; sourceTree = "<group>"; };
27AAA9852ACE34C800AF3C56 /* SwiftMessages+Banner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftMessages+Banner.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1687,6 +1689,7 @@
02F7010229EA192A004DEB5E /* dydxReceiptItemView.swift */,
0242E3DA2A9B14D0007605F9 /* dydxReceiptEquityView.swift */,
02770BAB2ABE11D4004BBFE5 /* dydxReceiptRewardsView.swift */,
27897DA12C94E71500196F21 /* ReceiptLoadingItemView.swift */,
);
path = Components;
sourceTree = "<group>";
Expand Down Expand Up @@ -2108,6 +2111,7 @@
27F624132BBDB4D400AB6D1A /* dydxTakeProfitStopLossInputAreaViewModel.swift in Sources */,
64A4DB6529662128008D8E20 /* dydxOrderbookView.swift in Sources */,
02EFE86A28FF0DEE00DEBF69 /* MarginUsage.swift in Sources */,
27897DA22C94E71500196F21 /* ReceiptLoadingItemView.swift in Sources */,
64A4DB59296620B4008D8E20 /* dydxTradeInputTimeInForceView.swift in Sources */,
27ED365C2AD735A800C159F5 /* dydxSecurityView.swift in Sources */,
029CBE7728F608F400259C1D /* dydxMarketTradesView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// dydxReceiptLoadingItemView.swift
// dydxUI
//
// Created by Mike Maguire on 6/11/24.
// Copyright © 2024 dYdX Trading Inc. All rights reserved.
//

import SwiftUI
import PlatformUI
import Utilities

public class dydxReceiptLoadingItemView: PlatformViewModel {
@Published public var title: String

public init(title: String) {
self.title = title
}

public static var previewValue: dydxReceiptChangeItemView {
let vm = dydxReceiptChangeItemView(title: "Title")
return vm
}

public override func createView(parentStyle: ThemeStyle = ThemeStyle.defaultStyle, styleKey: String? = nil) -> PlatformView {
PlatformView(viewModel: self, parentStyle: parentStyle, styleKey: styleKey) { [weak self] _ in
guard let self = self else { return AnyView(PlatformView.nilView) }
let textFontSize = ThemeFont.FontSize.small
return AnyView(
HStack(alignment: .top) {
Text(self.title)
.themeFont(fontSize: textFontSize)
.themeColor(foreground: .textTertiary)
.lineLimit(2)
Spacer()
ProgressView()
.progressViewStyle(.circular)
.tint(ThemeColor.SemanticColor.textSecondary.color)
.frame(height: ThemeSettings.shared.themeConfig.themeFont.uiFont(of: .base, fontSize: textFontSize)?.lineHeight)
}
)
}
}
}
Loading

0 comments on commit 2c842f1

Please sign in to comment.