diff --git a/Flipcash/Core/Controllers/Deep Links/Wallet/WalletConnection.swift b/Flipcash/Core/Controllers/Deep Links/Wallet/WalletConnection.swift index db350be7..32f26f65 100644 --- a/Flipcash/Core/Controllers/Deep Links/Wallet/WalletConnection.swift +++ b/Flipcash/Core/Controllers/Deep Links/Wallet/WalletConnection.swift @@ -82,7 +82,7 @@ public final class WalletConnection { if let code = url.queryItemValue(for: "errorCode") { if code == "4001" { - Analytics.walletCancel() + Analytics.track(event: Analytics.WalletEvent.cancel) pendingSwap = nil if processing != nil { @@ -212,7 +212,7 @@ public final class WalletConnection { let errorCount = results.count - submittedSignatures.count if errorCount == 0 { - Analytics.walletTransactionsSubmitted() + Analytics.track(event: Analytics.WalletEvent.transactionsSubmitted) // If this was a swap transaction, notify server via buy() if let pending, let firstSignature = submittedSignatures.first, let self { @@ -250,7 +250,7 @@ public final class WalletConnection { } } } else { - Analytics.walletTransactionsFailed() + Analytics.track(event: Analytics.WalletEvent.transactionsFailed) await MainActor.run { self?.showSomethingWentWrongDialog() } @@ -298,7 +298,7 @@ public final class WalletConnection { URLQueryItem(name: "nonce", value: nonce) ] - Analytics.walletConnect() + Analytics.track(event: Analytics.WalletEvent.connect) openExternalWallet(c.url!) } diff --git a/Flipcash/Core/Screens/Main/BalanceScreen.swift b/Flipcash/Core/Screens/Main/BalanceScreen.swift index df3b66de..f49fc839 100644 --- a/Flipcash/Core/Screens/Main/BalanceScreen.swift +++ b/Flipcash/Core/Screens/Main/BalanceScreen.swift @@ -87,6 +87,7 @@ struct BalanceScreen: View { private func handlePendingCurrencyInfo() { guard let mint = session.pendingCurrencyInfoMint else { return } + Analytics.tokenInfoOpened(from: .openedFromDeeplink, mint: mint) selectedMint = mint // Clear the pending mint @@ -162,6 +163,7 @@ struct BalanceScreen: View { if hasBalances { ForEach(currencyBalances) { balance in CurrencyBalanceRow(exchangedBalance: balance) { + Analytics.tokenInfoOpened(from: .openedFromWallet, mint: balance.stored.mint) selectedMint = balance.stored.mint } } @@ -199,6 +201,7 @@ struct BalanceScreen: View { Divider() Button { + Analytics.tokenInfoOpened(from: .openedFromWallet, mint: reservesBalance.stored.mint) selectedMint = reservesBalance.stored.mint } label: { HStack(spacing: 8) { diff --git a/Flipcash/Core/Screens/Main/Currency Info/CurrencyInfoScreen.swift b/Flipcash/Core/Screens/Main/Currency Info/CurrencyInfoScreen.swift index 526a0d8e..4f41ccd8 100644 --- a/Flipcash/Core/Screens/Main/Currency Info/CurrencyInfoScreen.swift +++ b/Flipcash/Core/Screens/Main/Currency Info/CurrencyInfoScreen.swift @@ -157,6 +157,7 @@ struct CurrencyInfoScreen: View { if !isUSDF { ToolbarItem(placement: .navigationBarTrailing) { Button { + Analytics.buttonTapped(name: .shareTokenInfo) let url = URL(string: "https://app.flipcash.com/token/\(mint.base58)")! ShareSheet.present(url: url) } label: { @@ -313,6 +314,7 @@ struct CurrencyInfoScreen: View { if balance.quarks > 0 { CodeButton(style: .filledSecondary, title: "Sell") { + Analytics.buttonTapped(name: .sell) isShowingSellAmountEntry = true } } @@ -329,7 +331,7 @@ struct CurrencyInfoScreen: View { .navigationDestinationCompat(item: Bindable(walletConnection).processing) { processing in SwapProcessingScreen( swapId: processing.swapId, - swapType: .buy, + swapType: .buyWithPhantom, mint: processing.mint, amount: processing.amount ) @@ -382,10 +384,12 @@ struct CurrencyInfoScreen: View { FundingSelectionSheet( reserveBalance: reserveBalance, onSelectReserves: { + Analytics.buttonTapped(name: .buyWithReserves) isShowingBuyAmountEntry = true isShowingFundingSelection = false }, onSelectPhantom: { + Analytics.buttonTapped(name: .buyWithPhantom) walletConnection.connectToPhantom() isShowingFundingSelection = false }, diff --git a/Flipcash/Core/Screens/Main/Currency Swap/CurrencyBuyAmountScreen.swift b/Flipcash/Core/Screens/Main/Currency Swap/CurrencyBuyAmountScreen.swift index c3c784c1..81d8a423 100644 --- a/Flipcash/Core/Screens/Main/Currency Swap/CurrencyBuyAmountScreen.swift +++ b/Flipcash/Core/Screens/Main/Currency Swap/CurrencyBuyAmountScreen.swift @@ -46,7 +46,7 @@ struct CurrencyBuyAmountScreen: View { .navigationDestination(for: CurrencyBuyPath.self) { step in switch step { case .processing(let swapId, let mint, let amount): - SwapProcessingScreen(swapId: swapId, swapType: .buy, mint: mint, amount: amount) + SwapProcessingScreen(swapId: swapId, swapType: .buyWithReserves, mint: mint, amount: amount) .environment(\.dismissParentContainer, { dismissAction() }) diff --git a/Flipcash/Core/Screens/Main/Currency Swap/SwapProcessingViewModel.swift b/Flipcash/Core/Screens/Main/Currency Swap/SwapProcessingViewModel.swift index f014d236..86f5baa2 100644 --- a/Flipcash/Core/Screens/Main/Currency Swap/SwapProcessingViewModel.swift +++ b/Flipcash/Core/Screens/Main/Currency Swap/SwapProcessingViewModel.swift @@ -27,10 +27,9 @@ class SwapProcessingViewModel { return "This Will Take a Minute" case .success: if let exchangedFiat, let mintMetadata { - switch swapType { - case .buy: + if swapType.isBuy { return "\(exchangedFiat.converted.formatted()) of \(mintMetadata.name)" - case .sell: + } else { return "\(exchangedFiat.converted.formatted()) of USD Reserves" } } @@ -65,10 +64,9 @@ class SwapProcessingViewModel { var navigationTitle: String { switch displayState { case .processing: - switch swapType { - case .buy: + if swapType.isBuy { "Purchasing \(mintMetadata?.name ?? "")" - case .sell: + } else { "Selling \(mintMetadata?.name ?? "")" } case .success: @@ -92,7 +90,6 @@ class SwapProcessingViewModel { private let swapType: SwapType private let mint: PublicKey private let amount: ExchangedFiat - // MARK: - Init - init(swapId: SwapId, swapType: SwapType, mint: PublicKey, amount: ExchangedFiat) { @@ -132,10 +129,13 @@ class SwapProcessingViewModel { switch metadata.state { case .finalized: setSwapDetails() + trackTransaction(successful: true) displayState = .success case .failed, .cancelled: + trackTransaction(successful: false) displayState = .failed case .unknown, .created, .funding, .funded, .submitting, .cancelling: + trackTransaction(successful: false) displayState = .failed } } catch is CancellationError { @@ -153,6 +153,17 @@ class SwapProcessingViewModel { private func setSwapDetails() { exchangedFiat = amount } + + private func trackTransaction(successful: Bool) { + switch swapType { + case .buyWithReserves: + Analytics.tokenPurchase(method: .purchaseWithReserves, exchangedFiat: amount, successful: successful) + case .buyWithPhantom: + Analytics.tokenPurchase(method: .purchaseWithPhantom, exchangedFiat: amount, successful: successful) + case .sell: + Analytics.tokenSell(exchangedFiat: amount, successful: successful) + } + } } // MARK: - DisplayState - @@ -168,6 +179,14 @@ extension SwapProcessingViewModel { // MARK: - SwapType - enum SwapType { - case buy + case buyWithReserves + case buyWithPhantom case sell + + var isBuy: Bool { + switch self { + case .buyWithReserves, .buyWithPhantom: true + case .sell: false + } + } } diff --git a/Flipcash/Core/Screens/Main/GiveViewModel.swift b/Flipcash/Core/Screens/Main/GiveViewModel.swift index 905d6977..9164578a 100644 --- a/Flipcash/Core/Screens/Main/GiveViewModel.swift +++ b/Flipcash/Core/Screens/Main/GiveViewModel.swift @@ -161,6 +161,9 @@ class GiveViewModel: ObservableObject { private func presentDeposit() { depositMint = selectedBalance?.stored.mint + if let depositMint { + Analytics.tokenInfoOpened(from: .openedFromGive, mint: depositMint) + } } // MARK: - Errors - diff --git a/Flipcash/Core/Screens/Onboarding/OnboardingViewModel.swift b/Flipcash/Core/Screens/Onboarding/OnboardingViewModel.swift index ac9b1c59..f37c2c55 100644 --- a/Flipcash/Core/Screens/Onboarding/OnboardingViewModel.swift +++ b/Flipcash/Core/Screens/Onboarding/OnboardingViewModel.swift @@ -80,7 +80,7 @@ class OnboardingViewModel: ObservableObject { navigateToAccessKey() - Analytics.buttonTapped(name: .buttonCreateAccount) + Analytics.buttonTapped(name: .createAccount) } func saveToPhotosAction() { @@ -114,7 +114,7 @@ class OnboardingViewModel: ObservableObject { } } - Analytics.buttonTapped(name: .buttonSaveAccessKey) + Analytics.buttonTapped(name: .saveAccessKey) } func wroteDownAction() { @@ -129,7 +129,7 @@ class OnboardingViewModel: ObservableObject { try await self?.completeAccountCreation() } - Analytics.buttonTapped(name: .buttonWroteAccessKey) + Analytics.buttonTapped(name: .wroteAccessKey) }; .cancel() } @@ -234,7 +234,7 @@ class OnboardingViewModel: ObservableObject { completeOnboardingAndLogin() } - Analytics.buttonTapped(name: .buttonAllowCamera) + Analytics.buttonTapped(name: .allowCamera) } func cancelPendingPurchaseAction() { @@ -245,7 +245,7 @@ class OnboardingViewModel: ObservableObject { navigateToRoot() - Analytics.cancelPendingPurchase() + Analytics.track(event: Analytics.GeneralEvent.cancelPendingPurchase) } func allowPushPermissionsAction() { @@ -256,13 +256,13 @@ class OnboardingViewModel: ObservableObject { navigateToCameraAccessScreen() } - Analytics.buttonTapped(name: .buttonAllowPush) + Analytics.buttonTapped(name: .allowPush) } func skipPushPermissionsAction() { navigateToCameraAccessScreen() - Analytics.buttonTapped(name: .buttonSkipPush) + Analytics.buttonTapped(name: .skipPush) } // MARK: - Purchase - @@ -337,7 +337,7 @@ class OnboardingViewModel: ObservableObject { sessionAuthenticator.completeLogin(with: initializedAccount) - Analytics.track(event: .completeOnboarding) + Analytics.track(event: Analytics.GeneralEvent.completeOnboarding) } // MARK: - Pending Transactions - diff --git a/Flipcash/Core/Screens/Onramp/OnrampViewModel.swift b/Flipcash/Core/Screens/Onramp/OnrampViewModel.swift index 85a42956..92b0a9da 100644 --- a/Flipcash/Core/Screens/Onramp/OnrampViewModel.swift +++ b/Flipcash/Core/Screens/Onramp/OnrampViewModel.swift @@ -285,13 +285,13 @@ class OnrampViewModel: ObservableObject { } if origin.rawValue < Origin.phone.rawValue, !isPhoneVerified { - Analytics.onrampShowEnterPhone() + Analytics.track(event: Analytics.OnrampEvent.showEnterPhone) onrampPath.append(.enterPhoneNumber) return } if origin.rawValue < Origin.email.rawValue, !isEmailVerified { - Analytics.onrampShowEnterEmail() + Analytics.track(event: Analytics.OnrampEvent.showEnterEmail) onrampPath.append(.enterEmail) return } @@ -308,7 +308,7 @@ class OnrampViewModel: ObservableObject { isShowingVerificationFlow = false createOrder() } else { - Analytics.onrampShowVerificationInfo() + Analytics.track(event: Analytics.OnrampEvent.showVerificationInfo) isShowingVerificationFlow = true } } @@ -343,7 +343,7 @@ class OnrampViewModel: ObservableObject { func customAmountAction() { selectedPreset = nil isShowingAmountEntryScreen = true - Analytics.onrampEnterCustomAmount() + Analytics.track(event: Analytics.OnrampEvent.enterCustomAmount) } func customAmountEnteredAction() { @@ -394,7 +394,7 @@ class OnrampViewModel: ObservableObject { try await Task.delay(milliseconds: 500) onrampPath.append(.confirmPhoneNumberCode) - Analytics.onrampShowConfirmPhone() + Analytics.track(event: Analytics.OnrampEvent.showConfirmPhone) try await Task.delay(milliseconds: 500) } @@ -502,7 +502,7 @@ class OnrampViewModel: ObservableObject { try await Task.delay(milliseconds: 500) onrampPath.append(.confirmEmailCode) - Analytics.onrampShowConfirmEmail() + Analytics.track(event: Analytics.OnrampEvent.showConfirmEmail) try await Task.delay(milliseconds: 500) } diff --git a/Flipcash/Core/Session/SessionAuthenticator.swift b/Flipcash/Core/Session/SessionAuthenticator.swift index f5ab0efd..2b676949 100644 --- a/Flipcash/Core/Session/SessionAuthenticator.swift +++ b/Flipcash/Core/Session/SessionAuthenticator.swift @@ -76,7 +76,7 @@ final class SessionAuthenticator: ObservableObject { do { if let account = try await self?.initialize(using: keyAccount.mnemonic, isRegistration: false) { self?.completeLogin(with: account) - Analytics.autoLoginComplete() + Analytics.track(event: Analytics.GeneralEvent.autoLoginComplete) } } catch { self?.logout() diff --git a/Flipcash/Utilities/Analytics.swift b/Flipcash/Utilities/Analytics.swift index 6b06f3fe..2ec32c2c 100644 --- a/Flipcash/Utilities/Analytics.swift +++ b/Flipcash/Utilities/Analytics.swift @@ -13,6 +13,14 @@ import FlipcashCore typealias AnalyticsValue = MixpanelType +protocol AnalyticsEvent { + var eventName: String { get } +} + +extension AnalyticsEvent where Self: RawRepresentable { + var eventName: String { rawValue } +} + enum Analytics { static func initialize() { @@ -28,19 +36,19 @@ enum Analytics { } } - static func track(event: Name, properties: [Property: AnalyticsValue]? = nil, error: Error? = nil) { + static func track(event: some AnalyticsEvent, properties: [Property: AnalyticsValue]? = nil, error: Error? = nil) { var container: [String: AnalyticsValue] = [:] - + properties?.forEach { key, value in container[key.rawValue] = value } - + if let error { let swiftError = error as NSError container["Error"] = "\(swiftError.domain).\(error):\(swiftError.code)" } - - track(event.rawValue, properties: container) + + track(event.eventName, properties: container) } // static func track(_ action: Action, properties: [Property: AnalyticsValue]? = nil) { diff --git a/Flipcash/Utilities/Events.swift b/Flipcash/Utilities/Events.swift index 5944b9bc..566f7401 100644 --- a/Flipcash/Utilities/Events.swift +++ b/Flipcash/Utilities/Events.swift @@ -8,14 +8,78 @@ import Foundation import FlipcashCore -// MARK: - General - +// MARK: - Domain Event Enums - extension Analytics { - static func autoLoginComplete() { - track(event: .autoLoginComplete) + enum GeneralEvent: String, AnalyticsEvent { + case autoLoginComplete = "Auto-login complete" + case completeOnboarding = "Complete Onboarding" + case cancelPendingPurchase = "Cancel Pending Purchase" + } + + enum AccountEvent: String, AnalyticsEvent { + case createAccount = "Create Account" + } + + enum ButtonEvent: String, AnalyticsEvent { + case createAccount = "Button: Create Account" + case saveAccessKey = "Button: Save Access Key" + case wroteAccessKey = "Button: Wrote Access Key" + case allowCamera = "Button: Allow Camera" + case allowPush = "Button: Allow Push" + case skipPush = "Button: Skip Push" + case buyWithReserves = "Button: Buy With Reserves" + case buyWithPhantom = "Button: Buy With Phantom" + case sell = "Button: Sell" + case shareTokenInfo = "Button: Share Token Info" + } + + enum TransferEvent: String, AnalyticsEvent { + case withdrawal = "Withdrawal" + case sendCashLink = "Send Cash Link" + case receiveCashLink = "Receive Cash Link" + case grabBill = "Grab Bill" + case giveBill = "Give Bill" + } + + enum OnrampEvent: String, AnalyticsEvent { + case showVerificationInfo = "Onramp: Show Verification Info" + case showEnterPhone = "Onramp: Show Enter Phone" + case showConfirmPhone = "Onramp: Show Confirm Phone" + case showEnterEmail = "Onramp: Show Enter Email" + case showConfirmEmail = "Onramp: Show Confirm Email" + case presetSelected = "Onramp: Amount Selected" + case enterCustomAmount = "Onramp: Enter Custom Amount" + case invokePayment = "Onramp: Invoke Payment" + case invokePaymentCustom = "Onramp: Invoke Payment Custom" + case completed = "Onramp: Completed" + } + + enum WalletEvent: String, AnalyticsEvent { + case connect = "Wallet: Connect" + case requestAmount = "Wallet: Request Amount" + case transactionsSubmitted = "Wallet: Transactions Submitted" + case transactionsFailed = "Wallet: Transactions Failed" + case cancel = "Wallet: Cancel" + } + + enum TokenInfoEvent: String, AnalyticsEvent { + case openedFromDeeplink = "Token Info: Opened From Deeplink" + case openedFromWallet = "Token Info: Opened From Wallet" + case openedFromGive = "Token Info: Opened From Give" + } + + enum TokenTransactionEvent: String, AnalyticsEvent { + case purchaseWithReserves = "Token Purchase With Reserves" + case purchaseWithPhantom = "Token Purchase With Phantom" + case sell = "Token Sell" } - - static func buttonTapped(name: Name) { +} + +// MARK: - General - + +extension Analytics { + static func buttonTapped(name: ButtonEvent) { track(event: name) } } @@ -23,14 +87,9 @@ extension Analytics { // MARK: - Account - extension Analytics { - - static func cancelPendingPurchase() { - track(event: .cancelPendingPurchase) - } - static func createAccount(owner: PublicKey) { track( - event: .createAccount, + event: AccountEvent.createAccount, properties: [ .ownerPublicKey: owner.base58, ] @@ -41,12 +100,11 @@ extension Analytics { // MARK: - Cash Transfer - extension Analytics { - static func withdrawal(exchangedFiat: ExchangedFiat?, successful: Bool, error: Error?) { var properties: [Property: AnalyticsValue] = [ .state: successful ? String.success : String.failure, ] - + if let exchangedFiat { properties[.usdc] = exchangedFiat.underlying.doubleValue properties[.mint] = exchangedFiat.mint.base58 @@ -55,19 +113,19 @@ extension Analytics { properties[.fx] = exchangedFiat.rate.fx.analyticsValue properties[.currency] = exchangedFiat.rate.currency.rawValue } - + track( - event: .withdrawal, + event: TransferEvent.withdrawal, properties: properties, error: error ) } - - static func transfer(event: Name, exchangedFiat: ExchangedFiat?, grabTime: Double?, successful: Bool, error: Error?) { + + static func transfer(event: TransferEvent, exchangedFiat: ExchangedFiat?, grabTime: Double?, successful: Bool, error: Error?) { var properties: [Property: AnalyticsValue] = [ .state: successful ? String.success : String.failure, ] - + if let exchangedFiat { properties[.usdc] = exchangedFiat.underlying.doubleValue properties[.mint] = exchangedFiat.mint.base58 @@ -76,28 +134,28 @@ extension Analytics { properties[.fx] = exchangedFiat.rate.fx.analyticsValue properties[.currency] = exchangedFiat.rate.currency.rawValue } - + if let grabTime { properties[.grabTime] = grabTime } - + track( event: event, properties: properties, error: error ) } - - static func transfer(event: Name, fiat: Quarks?, successful: Bool, error: Error?) { + + static func transfer(event: TransferEvent, fiat: Quarks?, successful: Bool, error: Error?) { var properties: [Property: AnalyticsValue] = [ .state: successful ? String.success : String.failure, ] - + if let fiat { properties[.usdc] = fiat.doubleValue properties[.quarks] = fiat.quarks.analyticsValue } - + track( event: event, properties: properties, @@ -109,81 +167,45 @@ extension Analytics { // MARK: - Onramp - extension Analytics { - static func onrampOpenedFromSettings() { - track(event: .onrampOpenedFromSettings) - } - - static func onrampOpenedFromGive() { - track(event: .onrampOpenedFromGive) - } - - static func onrampOpenedFromBalance() { - track(event: .onrampOpenedFromBalance) - } - - static func onrampShowVerificationInfo() { - track(event: .onrampShowVerificationInfo) - } - - static func onrampShowEnterPhone() { - track(event: .onrampShowEnterPhone) - } - - static func onrampShowConfirmPhone() { - track(event: .onrampShowConfirmPhone) - } - - static func onrampShowEnterEmail() { - track(event: .onrampShowEnterEmail) - } - - static func onrampShowConfirmEmail() { - track(event: .onrampShowConfirmEmail) - } - static func onrampAmountPresetSelected(amount: Quarks) { var properties: [Property: AnalyticsValue] = [:] - + properties[.fiat] = amount.doubleValue properties[.currency] = amount.currencyCode.rawValue - - track(event: .onrampPresetSelected, properties: properties) - } - - static func onrampEnterCustomAmount() { - track(event: .onrampEnterCustomAmount) + + track(event: OnrampEvent.presetSelected, properties: properties) } - + static func onrampInvokePayment(amount: Quarks) { var properties: [Property: AnalyticsValue] = [:] - + properties[.fiat] = amount.doubleValue properties[.currency] = amount.currencyCode.rawValue - - track(event: .onrampInvokePayment, properties: properties) + + track(event: OnrampEvent.invokePayment, properties: properties) } - + static func onrampInvokePaymentCustom(amount: Quarks) { var properties: [Property: AnalyticsValue] = [:] - + properties[.fiat] = amount.doubleValue properties[.currency] = amount.currencyCode.rawValue - - track(event: .onrampInvokePaymentCustom, properties: properties) + + track(event: OnrampEvent.invokePaymentCustom, properties: properties) } - + static func onrampCompleted(amount: Quarks?, successful: Bool, error: Error?) { var properties: [Property: AnalyticsValue] = [ .state: successful ? String.success : String.failure, ] - + if let amount { properties[.fiat] = amount.doubleValue properties[.currency] = amount.currencyCode.rawValue } - + track( - event: .onrampCompleted, + event: OnrampEvent.completed, properties: properties, error: error ) @@ -193,81 +215,53 @@ extension Analytics { // MARK: - Wallet - extension Analytics { - - static func walletConnect() { - track(event: .walletConnect) - } - static func walletRequestAmount(amount: Quarks) { var properties: [Property: AnalyticsValue] = [:] - + properties[.fiat] = amount.doubleValue properties[.currency] = amount.currencyCode.rawValue - - track(event: .walletRequestAmount, properties: properties) - } - - static func walletTransactionsSubmitted() { - track(event: .walletTransactionsSubmitted) - } - - static func walletTransactionsFailed() { - track(event: .walletTransactionsFailed) + + track(event: WalletEvent.requestAmount, properties: properties) } - - static func walletCancel() { - track(event: .walletCancel) +} + +// MARK: - Token Info - + +extension Analytics { + static func tokenInfoOpened(from event: TokenInfoEvent, mint: PublicKey) { + track(event: event, properties: [.mint: mint.base58]) } } -// MARK: - Definitions - +// MARK: - Token Transactions - extension Analytics { - enum Name: String { - case createAccount = "Create Account" - case withdrawal = "Withdrawal" - case sendCashLink = "Send Cash Link" - case receiveCashLink = "Receive Cash Link" - case grabBill = "Grab Bill" - case giveBill = "Give Bill" - - case buttonCreateAccount = "Button: Create Account" - case buttonSaveAccessKey = "Button: Save Access Key" - case buttonWroteAccessKey = "Button: Wrote Access Key" - case buttonAllowCamera = "Button: Allow Camera" - case buttonAllowPush = "Button: Allow Push" - case buttonSkipPush = "Button: Skip Push" - - case autoLoginComplete = "Auto-login complete" - case completeOnboarding = "Complete Onboarding" - - case onrampOpenedFromSettings = "Onramp: Opened From Settings" - case onrampOpenedFromBalance = "Onramp: Opened From Balance" - case onrampOpenedFromGive = "Onramp: Opened From Give" - case onrampShowVerificationInfo = "Onramp: Show Verification Info" - case onrampShowEnterPhone = "Onramp: Show Enter Phone" - case onrampShowConfirmPhone = "Onramp: Show Confirm Phone" - case onrampShowEnterEmail = "Onramp: Show Enter Email" - case onrampShowConfirmEmail = "Onramp: Show Confirm Email" - case onrampPresetSelected = "Onramp: Amount Selected" - case onrampEnterCustomAmount = "Onramp: Enter Custom Amount" - case onrampInvokePayment = "Onramp: Invoke Payment" - case onrampInvokePaymentCustom = "Onramp: Invoke Payment Custom" - case onrampCompleted = "Onramp: Completed" - - case walletConnect = "Wallet: Connect" - case walletRequestAmount = "Wallet: Request Amount" - case walletTransactionsSubmitted = "Wallet: Transactions Submitted" - case walletTransactionsFailed = "Wallet: Transactions Failed" - case walletCancel = "Wallet: Cancel" - - case cancelPendingPurchase = "Cancel Pending Purchase" + static func tokenPurchase(method: TokenTransactionEvent, exchangedFiat: ExchangedFiat, successful: Bool, error: Error? = nil) { + let properties: [Property: AnalyticsValue] = [ + .state: successful ? String.success : String.failure, + .mint: exchangedFiat.mint.base58, + .fiat: exchangedFiat.converted.doubleValue, + .currency: exchangedFiat.rate.currency.rawValue, + ] + track(event: method, properties: properties, error: error) + } + + static func tokenSell(exchangedFiat: ExchangedFiat, successful: Bool, error: Error? = nil) { + let properties: [Property: AnalyticsValue] = [ + .state: successful ? String.success : String.failure, + .mint: exchangedFiat.mint.base58, + .fiat: exchangedFiat.converted.doubleValue, + .currency: exchangedFiat.rate.currency.rawValue, + ] + track(event: TokenTransactionEvent.sell, properties: properties, error: error) } } +// MARK: - Definitions - + extension Analytics { enum Property: String { - + case id = "ID" case ownerPublicKey = "Owner Public Key" case autoCompleteCount = "Auto-complete count" @@ -275,7 +269,7 @@ extension Analytics { case result = "Result" case grabTime = "Grab Time" case time = "Time" - + case state = "State" case quarks = "Quarks" case usdc = "USDC" @@ -285,7 +279,7 @@ extension Analytics { case fx = "Exchange Rate" case animation = "Animation" case rendezvous = "Rendezvous" - + case type = "Type" case error = "Error" }