Skip to content

Commit

Permalink
mega vaults testing feedback (#278)
Browse files Browse the repository at this point in the history
* handle empty subaccount

* change megavault row item, prashan feedback

* adjust what is displayed in positions list

* move deposit/withdraw buttons

* fix roundings

* prevent flashing of position icons

---------

Co-authored-by: Mike <[email protected]>
  • Loading branch information
mike-dydx and mike-dydx authored Oct 22, 2024
1 parent 3b23bc6 commit 5a364d9
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 103 deletions.
14 changes: 13 additions & 1 deletion dydx/dydxFormatter/dydxFormatter/dydxFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public final class dydxFormatter: NSObject, SingletonProtocol {
let postfix = ["", "K", "M", "B", "T"]
var value = number.decimalValue
var index = 0
while value > 1000.0 && index < (postfix.count - 1) {
while value.magnitude > 1000.0 && index < (postfix.count - 1) {
value = value / 1000.0
index += 1
}
Expand All @@ -242,6 +242,18 @@ public final class dydxFormatter: NSObject, SingletonProtocol {
return nil
}

public func condensedDollar(number: Double?, digits: Int = 2) -> String? {
if let number = number {
let text = condensed(number: NSNumber(value: number), digits: digits)
if text?.first == "-" {
return "-$\(text?.dropFirst() ?? "")"
} else {
return "$\(text ?? "")"
}
}
return nil
}

/// formats the number as "$" or "-$" of "+$" prefixed
/// - Parameters:
/// - number: the number to format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class dydxPortfolioPositionsViewPresenter: HostedViewPresenter<dydxPortfolioPosi
if onboarded {
let vaultBalance = vault?.account?.balanceUsdc?.doubleValue ?? 0
let vaultApy = vault?.details?.thirtyDayReturnPercent?.doubleValue
self.viewModel?.vaultBalance = dydxFormatter.shared.dollar(number: vaultBalance, digits: 2)
self.viewModel?.vaultBalance = dydxFormatter.shared.dollar(number: vaultBalance, digits: 0)
self.viewModel?.vaultApy = vaultApy
} else {
self.viewModel?.vaultBalance = nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,13 @@ private class dydxVaultDepositWithdrawConfirmationViewPresenter: HostedViewPrese
private func update(subaccount: Subaccount?, vault: Abacus.Vault, hasAcknowledgedHighSlippage: Bool, hasAcknowledgedVaultTos: Bool) {
formValidationRequest?.cancel()

guard let subaccount = subaccount, let transferType else {
guard let transferType else {
Router.shared?.navigate(to: RoutingRequest(path: "/action/dismiss"), animated: true, completion: nil)
return
}

let accountData = Abacus.VaultFormAccountData(marginUsage: subaccount.marginUsage?.current,
freeCollateral: subaccount.freeCollateral?.current,
let accountData = Abacus.VaultFormAccountData(marginUsage: subaccount?.marginUsage?.current,
freeCollateral: subaccount?.freeCollateral?.current,
canViewAccount: true)

let formData = VaultFormData(action: transferType.formAction,
Expand Down Expand Up @@ -245,7 +245,7 @@ private class dydxVaultDepositWithdrawConfirmationViewPresenter: HostedViewPrese
/// only necessary for withdrawals
private func fetchSlippageAndUpdate(formData: Abacus.VaultFormData,
accountData: Abacus.VaultFormAccountData,
subaccount: Abacus.Subaccount,
subaccount: Abacus.Subaccount?,
vault: Abacus.Vault,
hasAcknowledgedHighSlippage: Bool) {
formValidationRequest = Task { [weak self] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,8 @@ private class dydxVaultDepositWithdrawViewPresenter: HostedViewPresenter<dydxVau
private func update(subaccount: Subaccount?, vault: Abacus.Vault, hasOnboarded: Bool, amount: Double, transferType: dydxViews.VaultTransferType) {
formValidationRequest?.cancel()

guard let subaccount = subaccount else {
Router.shared?.navigate(to: RoutingRequest(path: "/action/dismiss"), animated: true, completion: nil)
return
}

let accountData = Abacus.VaultFormAccountData(marginUsage: subaccount.marginUsage?.current,
freeCollateral: subaccount.freeCollateral?.current,
let accountData = Abacus.VaultFormAccountData(marginUsage: subaccount?.marginUsage?.current ?? 0,
freeCollateral: subaccount?.freeCollateral?.current ?? 0,
canViewAccount: hasOnboarded.asKotlinBoolean)

let formData = VaultFormData(action: transferType.formAction,
Expand Down Expand Up @@ -134,7 +129,7 @@ private class dydxVaultDepositWithdrawViewPresenter: HostedViewPresenter<dydxVau
/// only necessary for withdrawals
private func fetchSlippageAndUpdate(formData: Abacus.VaultFormData,
accountData: Abacus.VaultFormAccountData,
subaccount: Abacus.Subaccount,
subaccount: Abacus.Subaccount?,
hasOnboarded: Bool,
vault: Abacus.Vault,
amount: Double,
Expand Down Expand Up @@ -163,38 +158,32 @@ private class dydxVaultDepositWithdrawViewPresenter: HostedViewPresenter<dydxVau
}

private func update(subaccount: Subaccount?, vault: Abacus.Vault, hasOnboarded: Bool, amount: Double, transferType: dydxViews.VaultTransferType, formValidationResult: VaultFormValidationResult) {
guard let subaccount = subaccount else {
Router.shared?.navigate(to: RoutingRequest(path: "/action/dismiss"), animated: true, completion: nil)
return
}
updateMaxAmount(subaccount: subaccount, vault: vault, transferType: transferType)
updateSubmitState(formValidationResult: formValidationResult)
updateReceiptItems(formValidationResult: formValidationResult, subaccount: subaccount, vault: vault, amount: amount, transferType: transferType)
updateSubmitAction(amount: amount, transferType: transferType)
updateErrorAlert(formValidationResult: formValidationResult)
}

private func updateMaxAmount(subaccount: Abacus.Subaccount, vault: Abacus.Vault?, transferType: dydxViews.VaultTransferType) {
private func updateMaxAmount(subaccount: Abacus.Subaccount?, vault: Abacus.Vault?, transferType: dydxViews.VaultTransferType) {
switch transferType {
case .deposit:
if let roundedFreeCollateral = subaccount.freeCollateral?.current?.doubleValue.round(to: 2, rule: .towardZero) {
viewModel?.maxAmount = roundedFreeCollateral
}
let roundedFreeCollateral = subaccount?.freeCollateral?.current?.doubleValue.round(to: 2, rule: .towardZero) ?? 0
viewModel?.maxAmount = roundedFreeCollateral
case .withdraw:
if let roundedBalance = vault?.account?.balanceUsdc?.doubleValue.round(to: 2, rule: .towardZero) {
viewModel?.maxAmount = roundedBalance
}
let roundedBalance = vault?.account?.balanceUsdc?.doubleValue.round(to: 2, rule: .towardZero) ?? 0
viewModel?.maxAmount = roundedBalance
}
}

private func updateSubmitState(formValidationResult: VaultFormValidationResult) {
viewModel?.submitState = formValidationResult.errors.isEmpty ? .enabled : .disabled
}

private func updateReceiptItems(formValidationResult: VaultFormValidationResult, subaccount: Abacus.Subaccount, vault: Abacus.Vault, amount: Double, transferType: dydxViews.VaultTransferType) {
private func updateReceiptItems(formValidationResult: VaultFormValidationResult, subaccount: Abacus.Subaccount?, vault: Abacus.Vault, amount: Double, transferType: dydxViews.VaultTransferType) {
viewModel?.curVaultBalance = vault.account?.balanceUsdc?.doubleValue ?? 0
viewModel?.curFreeCollateral = subaccount.freeCollateral?.current?.doubleValue ?? 0
viewModel?.curMarginUsage = subaccount.marginUsage?.current?.doubleValue ?? 0
viewModel?.curFreeCollateral = subaccount?.freeCollateral?.current?.doubleValue ?? 0
viewModel?.curMarginUsage = subaccount?.marginUsage?.current?.doubleValue ?? 0

viewModel?.postVaultBalance = viewModel?.curVaultBalance == formValidationResult.summaryData.vaultBalance?.doubleValue ? nil : formValidationResult.summaryData.vaultBalance?.doubleValue
viewModel?.postFreeCollateral = viewModel?.curFreeCollateral == formValidationResult.summaryData.freeCollateral?.doubleValue ? nil : formValidationResult.summaryData.freeCollateral?.doubleValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,18 @@ private class dydxVaultViewBuilderPresenter: HostedViewPresenter<dydxVaultViewMo
viewModel?.totalValueLocked = vault?.details?.totalValue?.doubleValue
viewModel?.thirtyDayReturnPercent = vault?.details?.thirtyDayReturnPercent?.doubleValue
viewModel?.vaultBalance = vault?.account?.balanceUsdc?.doubleValue
viewModel?.allTimeReturnUsdc = vault?.account?.allTimeReturnUsdc?.doubleValue
viewModel?.allTimeReturnUsdc = vault?.account?.allTimeReturnUsdc?.doubleValue.round(to: 2)

viewModel?.positions = vault?.positions?.positions?.map { (position) -> dydxVaultPositionViewModel? in
let newPositions = vault?.positions?.positions?.map { (position) -> dydxVaultPositionViewModel? in
guard let leverage = position.currentLeverageMultiple?.doubleValue,
let notionalValue = position.currentPosition?.usdc?.doubleValue,
let positionSize = position.currentPosition?.asset?.doubleValue,
let marketId = position.marketId,
// special case for fake USDC market to show unused margin
let assetId = marketId == "USDC-USD" ? "USDC" : marketMap[marketId]?.assetId,
let displayId = assetMap[assetId]?.id ?? marketMap[marketId]?.displayId
else { return nil }
let equity = position.marginUsdc?.doubleValue ?? 0
let notionalValue = position.currentPosition?.usdc?.doubleValue ?? 0
let positionSize = position.currentPosition?.asset?.doubleValue ?? 0
let iconType: PlatformIconViewModel.IconType
let tokenUnitPrecision: Int
if marketId == "USDC-USD" {
Expand All @@ -109,19 +110,40 @@ private class dydxVaultViewBuilderPresenter: HostedViewPresenter<dydxVaultViewMo
iconType = .init(url: URL(string: assetMap[assetId]?.resources?.imageUrl ?? ""), placeholderText: assetId.first?.uppercased())
tokenUnitPrecision = marketMap[marketId]?.configs?.displayStepSizeDecimals?.intValue ?? 2
}
return dydxVaultPositionViewModel(displayId: displayId,
iconType: iconType,
side: positionSize > 0 ? .long : .short,
leverage: leverage,
notionalValue: notionalValue,
positionSize: positionSize.magnitude,
tokenUnitPrecision: tokenUnitPrecision,
pnlAmount: position.thirtyDayPnl?.absolute?.doubleValue,
pnlPercentage: position.thirtyDayPnl?.percent?.doubleValue,
sparklineValues: position.thirtyDayPnl?.sparklinePoints?.map({ $0.doubleValue }))

// only create new view model instance if it does not already exist
if let existing = viewModel?.positions?[marketId] {
return existing.updated(
marketId: marketId,
displayId: displayId,
iconType: iconType,
side: positionSize > 0 ? .long : .short,
leverage: leverage,
equity: equity,
notionalValue: notionalValue,
positionSize: positionSize.magnitude,
tokenUnitPrecision: tokenUnitPrecision,
pnlAmount: position.thirtyDayPnl?.absolute?.doubleValue,
pnlPercentage: position.thirtyDayPnl?.percent?.doubleValue,
sparklineValues: position.thirtyDayPnl?.sparklinePoints?.map({ $0.doubleValue }))
} else {
return dydxVaultPositionViewModel(
marketId: marketId,
displayId: displayId,
iconType: iconType,
side: positionSize > 0 ? .long : .short,
leverage: leverage,
equity: equity,
notionalValue: notionalValue,
positionSize: positionSize.magnitude,
tokenUnitPrecision: tokenUnitPrecision,
pnlAmount: position.thirtyDayPnl?.absolute?.doubleValue,
pnlPercentage: position.thirtyDayPnl?.percent?.doubleValue,
sparklineValues: position.thirtyDayPnl?.sparklinePoints?.map({ $0.doubleValue }))
}
}
.compactMap { $0 }
.sorted(by: { $0.notionalValue > $1.notionalValue })
viewModel?.positions = Dictionary(uniqueKeysWithValues: newPositions?.map({ ( $0.marketId, $0) }) ?? [])
}

private func updateChartState(vault: Abacus.Vault?, valueType: dydxVaultChartViewModel.ValueTypeOption, timeType: dydxVaultChartViewModel.ValueTimeOption) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,28 +340,15 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel {
public var apyAccessory: some View {
if let vaultApy, let vaultApyText = dydxFormatter.shared.percent(number: vaultApy, digits: 2) {
Text(vaultApyText)
.themeFont(fontSize: .smaller)
.themeFont(fontSize: .medium)
.padding(.horizontal, 4)
.padding(.vertical, 2)
.themeColor(foreground: vaultApy < 0 ? ThemeSettings.negativeColor : ThemeSettings.positiveColor)
.themeColor(background: vaultApy < 0 ? ThemeSettings.negativeColorLayer : ThemeSettings.positiveColorLayer)
.cornerRadius(4)
.cornerRadius(8)
}
}

public var megaVaultBalanceRowHeader: some View {
HStack(spacing: 0) {
Text(localizerPathKey: "APP.GENERAL.DETAILS")
.themeFont(fontType: .plus, fontSize: .small)
.themeColor(foreground: .textTertiary)
Spacer()
Text(localizerPathKey: "APP.VAULTS.YOUR_VAULT_BALANCE")
.themeFont(fontType: .plus, fontSize: .small)
.themeColor(foreground: .textTertiary)
}
.padding(.horizontal, 16)
}

@ViewBuilder
public var megaVaultBalanceRow: some View {
if let vaultBalance {
Expand All @@ -372,11 +359,9 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel {
templateColor: nil)
.createView()
Color.clear.frame(width: 16)
Text(localizerPathKey: "APP.VAULTS.MEGAVAULT")
Text(localizerPathKey: "APP.VAULTS.YOUR_VAULT_BALANCE")
.themeFont(fontSize: .medium)
.themeColor(foreground: .textSecondary)
Color.clear.frame(width: 6)
apyAccessory
Spacer()
Text(vaultBalance)
.themeFont(fontSize: .small)
Expand All @@ -392,19 +377,19 @@ public class dydxPortfolioPositionsViewModel: PlatformViewModel {
public var megaVaultSection: some View {
if dydxBoolFeatureFlag.isVaultEnabled.isEnabled && shouldDisplayVaultSection {
VStack(spacing: 16) {
Text(localizerPathKey: "APP.VAULTS.MEGAVAULT")
.themeFont(fontType: .plus, fontSize: .larger)
.themeColor(foreground: .textPrimary)
.fixedSize()
.leftAligned()
VStack(spacing: 8) {
megaVaultBalanceRowHeader
megaVaultBalanceRow
HStack(spacing: 8) {
Text(localizerPathKey: "APP.VAULTS.MEGAVAULT")
.themeFont(fontType: .plus, fontSize: .larger)
.themeColor(foreground: .textPrimary)
apyAccessory
}
.leftAligned()
megaVaultBalanceRow
.onTapGesture { [weak self] in
self?.vaultTapAction?()
}
}
.onTapGesture { [weak self] in
self?.vaultTapAction?()
}

}
}

Expand Down
Loading

0 comments on commit 5a364d9

Please sign in to comment.