Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MOB-308: iOS: Handle deposit flow when user onboarded via Desktop Scan #108

Merged
merged 1 commit into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions PlatformUI/PlatformUI/Components/Buttons/PlatformButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public enum PlatformButtonState {
}

public enum PlatformButtonType {
case defaultType, iconType, pill, small
case defaultType(fillWidth: Bool), iconType, pill, small
}

public class PlatformButtonViewModel<Content: PlatformViewModeling>: PlatformViewModel {
Expand All @@ -22,7 +22,10 @@ public class PlatformButtonViewModel<Content: PlatformViewModeling>: PlatformVie
@Published public var type: PlatformButtonType
@Published public var state: PlatformButtonState

public init(content: Content, type: PlatformButtonType = .defaultType, state: PlatformButtonState = .primary, action: @escaping () -> ()) {
public init(content: Content,
type: PlatformButtonType = .defaultType(fillWidth: true),
state: PlatformButtonState = .primary,
action: @escaping () -> ()) {
self.action = action
self.content = content
self.type = type
Expand All @@ -37,19 +40,25 @@ public class PlatformButtonViewModel<Content: PlatformViewModeling>: PlatformVie
return AnyView(
Group {
switch self.type {
case .defaultType:
case .defaultType(let fillWidth):
let button = Button(action: self.action) {
HStack {
Spacer()
if fillWidth {
Spacer()
}
self.content
.createView(parentStyle: style.themeFont(fontType: .bold), styleKey: self.buttonStyleKey)
Spacer()
if fillWidth {
Spacer()
}
}
}
.buttonStyle(BorderlessButtonStyle())
.disabled(disabled)
.padding(.all, 14)
.frame(maxWidth: .infinity)
.if(fillWidth) { view in
view.frame(maxWidth: .infinity)
}
.themeStyle(styleKey: self.buttonStyleKey, parentStyle: style)
.cornerRadius(8)

Expand Down
12 changes: 12 additions & 0 deletions PlatformUI/PlatformUI/DesignSystem/Theme/ThemeViewModifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -667,3 +667,15 @@ struct DisableBouncesModifier: ViewModifier {
}
}
}

// MARK: Conditional

public extension View {
@ViewBuilder func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
if condition {
transform(self)
} else {
self
}
}
}
19 changes: 9 additions & 10 deletions dydx/dydxPresenters/dydxPresenters/_v4/Actions/WalletAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public class WalletAction: NSObject, NavigableProtocol {
completion?(nil, true)

case "/action/wallet/disconnect":
WalletAction.shared?.disconnect(ethereumAddress: parser.asString(request?.params?["ethereumAddress"]))
let ethereumAddress = parser.asString(request?.params?["ethereumAddress"])
WalletAction.shared?.disconnect(ethereumAddress: ethereumAddress)
completion?(nil, true)

case "/action/wallet/etherscan":
Expand Down Expand Up @@ -64,18 +65,16 @@ private class WalletActionImp: WalletActionProtocol {
}

public func disconnect(ethereumAddress: String?) {
if let ethereumAddress = ethereumAddress {
let prompter = PrompterFactory.shared?.prompter()
let signout = PrompterAction(title: DataLocalizer.localize(path: "APP.GENERAL.SIGN_OUT"), style: .destructive, enabled: true) { [weak self] in
self?.reallyDisconnect(ethereumAddress: ethereumAddress)
}
let cancel = PrompterAction(title: DataLocalizer.localize(path: "APP.GENERAL.CANCEL"), style: .cancel, enabled: true, selection: nil)
prompter?.title = DataLocalizer.localize(path: "APP.GENERAL.SIGN_OUT_WARNING")
prompter?.prompt([signout, cancel])
let prompter = PrompterFactory.shared?.prompter()
let signout = PrompterAction(title: DataLocalizer.localize(path: "APP.GENERAL.SIGN_OUT"), style: .destructive, enabled: true) { [weak self] in
self?.reallyDisconnect()
}
let cancel = PrompterAction(title: DataLocalizer.localize(path: "APP.GENERAL.CANCEL"), style: .cancel, enabled: true, selection: nil)
prompter?.title = DataLocalizer.localize(path: "APP.GENERAL.SIGN_OUT_WARNING")
prompter?.prompt([signout, cancel])
}

private func reallyDisconnect(ethereumAddress: String) {
private func reallyDisconnect() {
AbacusStateManager.shared.disconnectAndReplaceCurrentWallet()
Tracking.shared?.log(event: "DisconnectWallet", data: nil)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,13 @@ private class dydxOnboardScanViewPresenter: HostedViewPresenter<dydxOnboardScanV
showingError = false
if let address = parser.asString(json["cosmosAddress"]), let mnemonic = parser.asString(json["mnemonic"]) {
// TODO: parse ethereum address when it becomes available in the Sync with Desktop QR Scan flow
AbacusStateManager.shared.setV4(ethereumAddress: address,
AbacusStateManager.shared.setV4(ethereumAddress: nil,
walletId: nil,
cosmoAddress: address,
mnemonic: mnemonic)
Router.shared?.navigate(to: RoutingRequest(path: "/portfolio", params: ["ethereumAddress": address]), animated: true, completion: nil)
Router.shared?.navigate(to: RoutingRequest(path: "/portfolio",
params: ["cosmoAddress": address, "mnemonic": mnemonic]),
animated: true, completion: nil)
} else {
showingError = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ private class dydxWalletListViewController: HostingViewController<PlatformView,

override public func arrive(to request: RoutingRequest?, animated: Bool) -> Bool {
if request?.path == "/onboard/wallets" {
let presenter = presenter as? dydxWalletListViewPresenterProtocol
presenter?.mobileOnly = (request?.params?["mobileOnly"] as? String) == "true"
presenter?.viewModel?.onScrollViewCreated = { [weak self] scrollView in
self?.scrollView = scrollView
}
Expand All @@ -45,9 +47,17 @@ private class dydxWalletListViewController: HostingViewController<PlatformView,

private protocol dydxWalletListViewPresenterProtocol: HostedViewPresenterProtocol {
var viewModel: dydxWalletListViewModel? { get }
var mobileOnly: Bool { get set }
}

private class dydxWalletListViewPresenter: HostedViewPresenter<dydxWalletListViewModel>, dydxWalletListViewPresenterProtocol {

var mobileOnly: Bool = false {
didSet {
updateWallets()
}
}

private var desktopSyncViewModel: dydxSyncDesktopViewModel = {
let viewModel = dydxSyncDesktopViewModel()
viewModel.onTap = {
Expand Down Expand Up @@ -108,6 +118,10 @@ private class dydxWalletListViewPresenter: HostedViewPresenter<dydxWalletListVie
}

let debugScan = UIDevice.current.isSimulator ? [debugScanViewModel] : []
viewModel?.items = [desktopSyncViewModel] + debugScan + installedWalletViewModels + uninstalledWalletViewModels
if mobileOnly {
viewModel?.items = installedWalletViewModels + uninstalledWalletViewModels
} else {
viewModel?.items = [desktopSyncViewModel] + debugScan + installedWalletViewModels + uninstalledWalletViewModels
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ class dydxProfileButtonsViewPresenter: HostedViewPresenter<dydxProfileButtonsVie
.map(\.currentWallet)
.prefix(1)
.sink { currentWallet in
if let ethereumAddress = currentWallet?.ethereumAddress {
Router.shared?.navigate(to: RoutingRequest(path: "/action/wallet/disconnect", params: ["ethereumAddress": ethereumAddress]), animated: true, completion: nil)
}
let ethereumAddress = currentWallet?.ethereumAddress ?? ""
Router.shared?.navigate(to: RoutingRequest(path: "/action/wallet/disconnect", params: ["ethereumAddress": ethereumAddress]), animated: true, completion: nil)
}
.store(in: &self.subscriptions)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ class dydxTransferDepositViewPresenter: HostedViewPresenter<dydxTransferDepositV
}
}

viewModel.connectWalletAction = {
let request = RoutingRequest(path: "/onboard/wallets",
params: ["mobileOnly": "true"])
Router.shared?.navigate(to: request, animated: true, completion: nil)
}

self.viewModel = viewModel

attachChildren(workers: childPresenters)
Expand Down Expand Up @@ -108,16 +114,19 @@ class dydxTransferDepositViewPresenter: HostedViewPresenter<dydxTransferDepositV
AbacusStateManager.shared.state.currentWallet
.map(\.?.ethereumAddress)
.removeDuplicates()
).sink { [weak self] (resources: TransferInputResources?, chain: String?, tokenAddress: String?, walletAddress: String?) in
).sink { [weak self] (resources: TransferInputResources?, chain: String?, tokenAddress: String?, ethereumAddress: String?) in
if let tokenAddress = tokenAddress,
let walletAddress = walletAddress,
let walletAddress = ethereumAddress,
walletAddress.starts(with: "dydx") == false,
let chain = chain,
let chainRpc = resources?.chainResources?[chain]?.rpc,
let tokenResource = resources?.tokenResources?[tokenAddress],
let tokenSymbol = tokenResource.symbol,
let tokenDecimals = tokenResource.decimals {
self?.viewModel?.showConnectWallet = false
self?.fetchTokenAmount(chainRpc: chainRpc, tokenSymbol: tokenSymbol, tokenAddress: tokenAddress, tokenDecimals: tokenDecimals.intValue, walletAddress: walletAddress)
} else {
self?.viewModel?.showConnectWallet = true
self?.ethereumInteractor = nil
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private class Wallets2ViewPresenter: HostedViewPresenter<Wallets2ViewModel> {
private func updateWalletState(walletState: dydxWalletState) {
viewModel?.walletConnections = walletState.wallets.map { wallet in
let viewModel = WalletConnectionViewModel()
viewModel.walletAddress = wallet.ethereumAddress
viewModel.walletAddress = wallet.ethereumAddress ?? wallet.cosmoAddress
viewModel.selected = wallet == walletState.currentWallet
viewModel.onTap = {
if let cosmoAddress = wallet.cosmoAddress, let mnemonic = wallet.mnemonic {
Expand All @@ -99,10 +99,11 @@ private class Wallets2ViewPresenter: HostedViewPresenter<Wallets2ViewModel> {
}

viewModel.openInEtherscanTapped = {
let ethereumAddress = wallet.ethereumAddress
let urlString = "https://etherscan.io/address/\(ethereumAddress)"
if let url = URL(string: urlString), URLHandler.shared?.canOpenURL(url) ?? false {
URLHandler.shared?.open(url, completionHandler: nil)
if let ethereumAddress = wallet.ethereumAddress {
let urlString = "https://etherscan.io/address/\(ethereumAddress)"
if let url = URL(string: urlString), URLHandler.shared?.canOpenURL(url) ?? false {
URLHandler.shared?.open(url, completionHandler: nil)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ public final class AbacusState {
public var onboarded: AnyPublisher<Bool, Never> {
walletState
.map { walletState in
if let currentWallet = walletState.currentWallet,
currentWallet.ethereumAddress.length > 0 {
return (currentWallet.cosmoAddress?.length ?? 0) > 0
}
return false
(walletState.currentWallet?.cosmoAddress?.length ?? 0) > 0
}
.removeDuplicates()
.share()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public final class AbacusStateManager: NSObject {
asyncStateManager.accountAddress = ethereumAddress
}

public func setV4(ethereumAddress: String, walletId: String?, cosmoAddress: String, mnemonic: String) {
public func setV4(ethereumAddress: String?, walletId: String?, cosmoAddress: String, mnemonic: String) {
CosmoJavascript.shared.connectWallet(mnemonic: mnemonic) { [weak self] _ in
if let self = self {
let wallet = dydxWalletInstance.V4(ethereumAddress: ethereumAddress, walletId: walletId, cosmoAddress: cosmoAddress, mnemonic: mnemonic)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public struct dydxWalletState: Codable, Equatable {
}

public struct dydxWalletInstance: Codable, Equatable {
public let ethereumAddress: String
public let ethereumAddress: String?
public let walletId: String?

// V4
Expand All @@ -72,15 +72,15 @@ public struct dydxWalletInstance: Codable, Equatable {
public var secret: String?
public var passPhrase: String?

static func V4(ethereumAddress: String, walletId: String?, cosmoAddress: String, mnemonic: String) -> Self {
static func V4(ethereumAddress: String?, walletId: String?, cosmoAddress: String, mnemonic: String) -> Self {
Self.init(ethereumAddress: ethereumAddress, walletId: walletId, cosmoAddress: cosmoAddress, mnemonic: mnemonic)
}

static func V3(ethereumAddress: String, walletId: String?, apiKey: String, secret: String, passPhrase: String) -> Self {
static func V3(ethereumAddress: String?, walletId: String?, apiKey: String, secret: String, passPhrase: String) -> Self {
Self.init(ethereumAddress: ethereumAddress, walletId: walletId, apiKey: apiKey, secret: secret, passPhrase: passPhrase)
}

private init(ethereumAddress: String, walletId: String?, cosmoAddress: String? = nil, mnemonic: String? = nil, subaccountNumber: String? = nil, apiKey: String? = nil, secret: String? = nil, passPhrase: String? = nil) {
private init(ethereumAddress: String?, walletId: String?, cosmoAddress: String? = nil, mnemonic: String? = nil, subaccountNumber: String? = nil, apiKey: String? = nil, secret: String? = nil, passPhrase: String? = nil) {
self.ethereumAddress = ethereumAddress
self.walletId = walletId
self.cosmoAddress = cosmoAddress
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ public struct DepositTransaction: AsyncStep {
private let depositTransactionV4: DepositTransactionV4?

public let transferInput: TransferInput
public let walletAddress: String
public let walletAddress: String?
public let walletId: String?

public init(transferInput: TransferInput, walletAddress: String, walletId: String?) {
public init(transferInput: TransferInput, walletAddress: String?, walletId: String?) {
self.transferInput = transferInput
self.walletAddress = walletAddress
self.walletId = walletId

if let chain = transferInput.chain, let token = transferInput.token,
if let walletAddress = walletAddress,
let chain = transferInput.chain, let token = transferInput.token,
let chainRpc = transferInput.resources?.chainResources?[chain]?.rpc,
let tokenAddress = transferInput.resources?.tokenResources?[token]?.address {
depositTransactionV4 = DepositTransactionV4(transferInput: transferInput,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public class dydxOnboardScanInstructionsViewModel: PlatformViewModel {
let buttonContent =
Text(DataLocalizer.localize(path: "APP.ONBOARDING.OPEN_QR_CODE_NEXT"))
.wrappedViewModel
PlatformButtonViewModel(content: buttonContent, type: .defaultType) { [weak self] in
PlatformButtonViewModel(content: buttonContent, type: .defaultType(fillWidth: true)) { [weak self] in
self?.ctaAction?()
}
.createView(parentStyle: style)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public class dydxRewardsHistoryViewModel: dydxTitledCardViewModel {
}
.wrappedInAnyView()
},
type: .defaultType,
type: .defaultType(fillWidth: true),
state: .secondary,
action: {
withAnimation { [weak self] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public class dydxRewardsLaunchIncentivesViewModel: PlatformViewModel {
}
.wrappedInAnyView()
}
return PlatformButtonViewModel(content: content, type: .defaultType, state: .secondary, action: self.aboutAction ?? {})
return PlatformButtonViewModel(content: content, type: .defaultType(fillWidth: true), state: .secondary, action: self.aboutAction ?? {})
.createView(parentStyle: parentStyle)
}

Expand All @@ -106,7 +106,7 @@ public class dydxRewardsLaunchIncentivesViewModel: PlatformViewModel {
}
.wrappedInAnyView()
}
return PlatformButtonViewModel(content: content, type: .defaultType, state: .primary, action: self.leaderboardAction ?? {})
return PlatformButtonViewModel(content: content, type: .defaultType(fillWidth: true), state: .primary, action: self.leaderboardAction ?? {})
.createView(parentStyle: parentStyle)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class dydxTransferDepositViewModel: PlatformViewModel {
inputType: .decimalDigits)
@Published public var ctaButton: dydxTradeInputCtaButtonViewModel? = dydxTradeInputCtaButtonViewModel()
@Published public var validationViewModel: dydxValidationViewModel? = dydxValidationViewModel()
@Published public var showConnectWallet = false
@Published public var connectWalletAction: (() -> Void)?

public init() { }

Expand All @@ -40,9 +42,23 @@ public class dydxTransferDepositViewModel: PlatformViewModel {
VStack {
Group {
VStack(spacing: 12) {
self.chainsComboBox?.createView(parentStyle: style)
self.tokensComboBox?.createView(parentStyle: style)
self.amountBox?.createView(parentStyle: style)
if self.showConnectWallet {
HStack(spacing: 8) {
Text(DataLocalizer.localize(path: "APP.V4_DEPOSIT.MOBILE_WALLET_REQUIRED"))
.themeFont(fontSize: .medium)

let content = Text(DataLocalizer.localize(path: "APP.GENERAL.CONNECT_WALLET")).lineLimit(1).wrappedViewModel
PlatformButtonViewModel(content: content,
type: .defaultType(fillWidth: false)) { [weak self] in
self?.connectWalletAction?()
}
.createView(parentStyle: style)
}
} else {
self.chainsComboBox?.createView(parentStyle: style)
self.tokensComboBox?.createView(parentStyle: style)
self.amountBox?.createView(parentStyle: style)
}
}
}

Expand Down
Loading
Loading