diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/activities/BraveWalletBaseActivity.java b/android/java/org/chromium/chrome/browser/crypto_wallet/activities/BraveWalletBaseActivity.java index 97aea1743c9f..14685ae5b42c 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/activities/BraveWalletBaseActivity.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/activities/BraveWalletBaseActivity.java @@ -73,6 +73,7 @@ public void onConnectionError(MojoException e) { if (mTxService != null) mTxService.close(); if (mEthTxManagerProxy != null) mEthTxManagerProxy.close(); if (mSolanaTxManagerProxy != null) mSolanaTxManagerProxy.close(); + if (mBraveWalletP3A != null) mBraveWalletP3A.close(); if (mBraveWalletService != null) mBraveWalletService.close(); mKeyringService = null; diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/ApproveTxBottomSheetDialogFragment.java b/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/ApproveTxBottomSheetDialogFragment.java index 3fa268034da8..d1a37f81d83c 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/ApproveTxBottomSheetDialogFragment.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/ApproveTxBottomSheetDialogFragment.java @@ -31,12 +31,16 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.tabs.TabLayout; +import org.chromium.base.CommandLine; import org.chromium.base.Log; import org.chromium.brave_wallet.mojom.AccountInfo; import org.chromium.brave_wallet.mojom.AssetRatioService; import org.chromium.brave_wallet.mojom.BlockchainRegistry; import org.chromium.brave_wallet.mojom.BlockchainToken; +import org.chromium.brave_wallet.mojom.BraveWalletConstants; +import org.chromium.brave_wallet.mojom.BraveWalletP3a; import org.chromium.brave_wallet.mojom.BraveWalletService; +import org.chromium.brave_wallet.mojom.CoinType; import org.chromium.brave_wallet.mojom.JsonRpcService; import org.chromium.brave_wallet.mojom.KeyringService; import org.chromium.brave_wallet.mojom.NetworkInfo; @@ -54,6 +58,7 @@ import org.chromium.chrome.browser.crypto_wallet.util.TokenUtils; import org.chromium.chrome.browser.crypto_wallet.util.TransactionUtils; import org.chromium.chrome.browser.crypto_wallet.util.Utils; +import org.chromium.chrome.browser.crypto_wallet.util.WalletConstants; import org.chromium.chrome.browser.util.TabUtils; import org.chromium.url.GURL; @@ -169,6 +174,15 @@ private KeyringService getKeyringService() { return null; } + private BraveWalletP3a getBraveWalletP3A() { + Activity activity = getActivity(); + if (activity instanceof BraveWalletBaseActivity) { + return ((BraveWalletBaseActivity) activity).getBraveWalletP3A(); + } + + return null; + } + @Override public void show(FragmentManager manager, String tag) { try { @@ -443,6 +457,7 @@ private void approveTransaction() { "approveTransaction", error.getProviderError(), errorMessage); return; } + reportTransactionForP3A(); mApproved = true; if (mTransactionConfirmationListener != null) { mTransactionConfirmationListener.onApproveTransaction(); @@ -451,6 +466,25 @@ private void approveTransaction() { }); } + private void reportTransactionForP3A() { + if (!WalletConstants.SEND_TRANSACTION_TYPES.contains(mTxInfo.txType) + && !(mCoinType == CoinType.FIL && mTxInfo.txType == TransactionType.OTHER)) { + return; + } + JsonRpcService jsonRpcService = getJsonRpcService(); + BraveWalletP3a braveWalletP3A = getBraveWalletP3A(); + assert jsonRpcService != null && braveWalletP3A != null; + + jsonRpcService.getNetwork(mCoinType, selectedNetwork -> { + boolean countTestNetworks = CommandLine.getInstance().hasSwitch( + BraveWalletConstants.P3A_COUNT_TEST_NETWORKS_SWITCH); + if (countTestNetworks + || !WalletConstants.KNOWN_TEST_CHAIN_IDS.contains(selectedNetwork.chainId)) { + braveWalletP3A.reportTransactionSent(mCoinType, true); + } + }); + } + private boolean canUpdateUi() { return isAdded() && getActivity() != null; } diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/util/Utils.java b/android/java/org/chromium/chrome/browser/crypto_wallet/util/Utils.java index b1ecf380aaf9..b619be1d233a 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/util/Utils.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/util/Utils.java @@ -75,7 +75,6 @@ import org.chromium.brave_wallet.mojom.ProviderError; import org.chromium.brave_wallet.mojom.TransactionInfo; import org.chromium.brave_wallet.mojom.TransactionStatus; -import org.chromium.brave_wallet.mojom.TransactionType; import org.chromium.brave_wallet.mojom.TxData; import org.chromium.brave_wallet.mojom.TxService; import org.chromium.chrome.R; diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletConstants.java b/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletConstants.java index 5730b45c6c05..a41468410fea 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletConstants.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletConstants.java @@ -94,4 +94,13 @@ public final class WalletConstants { public static final String SOL_INS_BPF = "BPFLoaderUpgradeab1e11111111111111111111111"; public static final String SOL_INS_SIG_VERIFY = "Ed25519SigVerify111111111111111111111111111"; public static final String SOL_INS_SECP = "KeccakSecp256k11111111111111111111111111111"; + + public static final List KNOWN_TEST_CHAIN_IDS = Arrays.asList( + BraveWalletConstants.GOERLI_CHAIN_ID, BraveWalletConstants.SEPOLIA_CHAIN_ID, + BraveWalletConstants.LOCALHOST_CHAIN_ID, BraveWalletConstants.SOLANA_TESTNET, + BraveWalletConstants.SOLANA_DEVNET, BraveWalletConstants.FILECOIN_TESTNET); + public static final List SEND_TRANSACTION_TYPES = Arrays.asList( + TransactionType.ETH_SEND, TransactionType.ERC20_TRANSFER, + TransactionType.SOLANA_SYSTEM_TRANSFER, TransactionType.SOLANA_SPL_TOKEN_TRANSFER, + TransactionType.SOLANA_SPL_TOKEN_TRANSFER_WITH_ASSOCIATED_TOKEN_ACCOUNT_CREATION); } diff --git a/browser/brave_wallet/brave_wallet_p3a_unittest.cc b/browser/brave_wallet/brave_wallet_p3a_unittest.cc index f3d96a8bbea5..c5dca93625fb 100644 --- a/browser/brave_wallet/brave_wallet_p3a_unittest.cc +++ b/browser/brave_wallet/brave_wallet_p3a_unittest.cc @@ -20,7 +20,8 @@ namespace brave_wallet { class BraveWalletP3AUnitTest : public testing::Test { public: - BraveWalletP3AUnitTest() { + BraveWalletP3AUnitTest() + : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { histogram_tester_ = std::make_unique(); } @@ -142,4 +143,31 @@ TEST_F(BraveWalletP3AUnitTest, ReportOnboardingAction) { 1); } +TEST_F(BraveWalletP3AUnitTest, TransactionSent) { + histogram_tester_->ExpectTotalCount(kEthTransactionSentHistogramName, 0); + histogram_tester_->ExpectTotalCount(kSolTransactionSentHistogramName, 0); + histogram_tester_->ExpectTotalCount(kFilTransactionSentHistogramName, 0); + + BraveWalletP3A* wallet_p3a = wallet_service_->GetBraveWalletP3A(); + + wallet_p3a->ReportTransactionSent(mojom::CoinType::ETH, true); + histogram_tester_->ExpectUniqueSample(kEthTransactionSentHistogramName, 1, 1); + + wallet_p3a->ReportTransactionSent(mojom::CoinType::SOL, true); + histogram_tester_->ExpectUniqueSample(kSolTransactionSentHistogramName, 1, 1); + + wallet_p3a->ReportTransactionSent(mojom::CoinType::FIL, true); + histogram_tester_->ExpectUniqueSample(kFilTransactionSentHistogramName, 1, 1); + + task_environment_.FastForwardBy(base::Days(4)); + histogram_tester_->ExpectUniqueSample(kEthTransactionSentHistogramName, 1, 5); + histogram_tester_->ExpectUniqueSample(kSolTransactionSentHistogramName, 1, 5); + histogram_tester_->ExpectUniqueSample(kFilTransactionSentHistogramName, 1, 5); + + task_environment_.FastForwardBy(base::Days(3)); + histogram_tester_->ExpectBucketCount(kEthTransactionSentHistogramName, 0, 1); + histogram_tester_->ExpectBucketCount(kSolTransactionSentHistogramName, 0, 1); + histogram_tester_->ExpectBucketCount(kFilTransactionSentHistogramName, 0, 1); +} + } // namespace brave_wallet diff --git a/browser/ui/webui/brave_wallet/wallet_page_ui.cc b/browser/ui/webui/brave_wallet/wallet_page_ui.cc index 6faecba7d16c..6b9648688689 100644 --- a/browser/ui/webui/brave_wallet/wallet_page_ui.cc +++ b/browser/ui/webui/brave_wallet/wallet_page_ui.cc @@ -8,6 +8,7 @@ #include #include +#include "base/command_line.h" #include "base/files/file_path.h" #include "brave/browser/brave_wallet/asset_ratio_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" @@ -25,6 +26,7 @@ #include "brave/components/brave_wallet/browser/keyring_service.h" #include "brave/components/brave_wallet/browser/swap_service.h" #include "brave/components/brave_wallet/browser/tx_service.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom-forward.h" #include "brave/components/brave_wallet_page/resources/grit/brave_wallet_page_generated_map.h" #include "brave/components/constants/webui_url_constants.h" #include "brave/components/l10n/common/localization_util.h" @@ -66,6 +68,9 @@ WalletPageUI::WalletPageUI(content::WebUI* web_ui) source->AddString("braveWalletTrezorBridgeUrl", kUntrustedTrezorURL); source->AddString("braveWalletNftBridgeUrl", kUntrustedNftURL); source->AddString("braveWalletMarketUiBridgeUrl", kUntrustedMarketURL); + source->AddBoolean(brave_wallet::mojom::kP3ACountTestNetworksLoadTimeKey, + base::CommandLine::ForCurrentProcess()->HasSwitch( + brave_wallet::mojom::kP3ACountTestNetworksSwitch)); content::WebUIDataSource::Add(profile, source); content::URLDataSource::Add(profile, std::make_unique(profile)); diff --git a/browser/ui/webui/brave_wallet/wallet_page_ui.h b/browser/ui/webui/brave_wallet/wallet_page_ui.h index 053cd0bae00b..f197e15aef5f 100644 --- a/browser/ui/webui/brave_wallet/wallet_page_ui.h +++ b/browser/ui/webui/brave_wallet/wallet_page_ui.h @@ -58,7 +58,7 @@ class WalletPageUI : public ui::MojoWebUIController, mojo::PendingReceiver brave_wallet_service, mojo::PendingReceiver - brave_wallet_p3a_receiver) override; + brave_wallet_p3a) override; std::unique_ptr page_handler_; std::unique_ptr wallet_handler_; diff --git a/browser/ui/webui/brave_wallet/wallet_panel_ui.cc b/browser/ui/webui/brave_wallet/wallet_panel_ui.cc index 22e952ee944a..ab4a3bef8689 100644 --- a/browser/ui/webui/brave_wallet/wallet_panel_ui.cc +++ b/browser/ui/webui/brave_wallet/wallet_panel_ui.cc @@ -9,6 +9,7 @@ #include #include "base/bind.h" +#include "base/command_line.h" #include "brave/browser/brave_wallet/asset_ratio_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" #include "brave/browser/brave_wallet/json_rpc_service_factory.h" @@ -24,6 +25,7 @@ #include "brave/components/brave_wallet/browser/keyring_service.h" #include "brave/components/brave_wallet/browser/swap_service.h" #include "brave/components/brave_wallet/browser/tx_service.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom-forward.h" #include "brave/components/brave_wallet_panel/resources/grit/brave_wallet_panel_generated_map.h" #include "brave/components/constants/webui_url_constants.h" #include "brave/components/l10n/common/localization_util.h" @@ -66,7 +68,9 @@ WalletPanelUI::WalletPanelUI(content::WebUI* web_ui) source->AddString("braveWalletTrezorBridgeUrl", kUntrustedTrezorURL); source->AddString("braveWalletNftBridgeUrl", kUntrustedNftURL); source->AddString("braveWalletMarketUiBridgeUrl", kUntrustedMarketURL); - + source->AddBoolean(brave_wallet::mojom::kP3ACountTestNetworksLoadTimeKey, + base::CommandLine::ForCurrentProcess()->HasSwitch( + brave_wallet::mojom::kP3ACountTestNetworksSwitch)); if (ShouldDisableCSPForTesting()) { source->DisableContentSecurityPolicy(); } @@ -115,7 +119,9 @@ void WalletPanelUI::CreatePanelHandler( mojo::PendingReceiver filecoin_tx_manager_proxy_receiver, mojo::PendingReceiver - brave_wallet_service_receiver) { + brave_wallet_service_receiver, + mojo::PendingReceiver + brave_wallet_p3a_receiver) { DCHECK(page); auto* profile = Profile::FromWebUI(web_ui()); DCHECK(profile); @@ -142,8 +148,11 @@ void WalletPanelUI::CreatePanelHandler( profile, std::move(solana_tx_manager_proxy_receiver)); brave_wallet::TxServiceFactory::BindFilTxManagerProxyForContext( profile, std::move(filecoin_tx_manager_proxy_receiver)); - brave_wallet::BraveWalletServiceFactory::BindForContext( - profile, std::move(brave_wallet_service_receiver)); + brave_wallet::BraveWalletService* wallet_service = + brave_wallet::BraveWalletServiceFactory::GetServiceForContext(profile); + wallet_service->Bind(std::move(brave_wallet_service_receiver)); + wallet_service->GetBraveWalletP3A()->Bind( + std::move(brave_wallet_p3a_receiver)); auto* blockchain_registry = brave_wallet::BlockchainRegistry::GetInstance(); if (blockchain_registry) { diff --git a/browser/ui/webui/brave_wallet/wallet_panel_ui.h b/browser/ui/webui/brave_wallet/wallet_panel_ui.h index 0b18fe6b5fe6..f28c81bdedba 100644 --- a/browser/ui/webui/brave_wallet/wallet_panel_ui.h +++ b/browser/ui/webui/brave_wallet/wallet_panel_ui.h @@ -65,7 +65,9 @@ class WalletPanelUI : public ui::MojoBubbleWebUIController, mojo::PendingReceiver fil_tx_manager_proxy, mojo::PendingReceiver - brave_wallet_service) override; + brave_wallet_service, + mojo::PendingReceiver + brave_wallet_p3a) override; std::unique_ptr panel_handler_; std::unique_ptr wallet_handler_; diff --git a/components/brave_wallet/browser/brave_wallet_p3a.cc b/components/brave_wallet/browser/brave_wallet_p3a.cc index 59ec64826953..407c598f81e1 100644 --- a/components/brave_wallet/browser/brave_wallet_p3a.cc +++ b/components/brave_wallet/browser/brave_wallet_p3a.cc @@ -7,11 +7,15 @@ #include +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/strings/string_number_conversions.h" +#include "base/time/time.h" #include "brave/components/brave_wallet/browser/brave_wallet_service.h" #include "brave/components/brave_wallet/browser/keyring_service.h" #include "brave/components/brave_wallet/browser/pref_names.h" #include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" namespace brave_wallet { @@ -22,6 +26,12 @@ const char kKeyringCreatedHistogramName[] = "Brave.Wallet.KeyringCreated"; const char kOnboardingConversionHistogramName[] = "Brave.Wallet.OnboardingConversion.2"; const char kEthProviderHistogramName[] = "Brave.Wallet.EthProvider"; +const char kEthTransactionSentHistogramName[] = + "Brave.Wallet.EthTransactionSent"; +const char kSolTransactionSentHistogramName[] = + "Brave.Wallet.SolTransactionSent"; +const char kFilTransactionSentHistogramName[] = + "Brave.Wallet.FilTransactionSent"; // Has the Wallet keyring been created? // 0) No, 1) Yes @@ -78,6 +88,12 @@ void BraveWalletP3A::Bind( receivers_.Add(this, std::move(receiver)); } +void BraveWalletP3A::Update() { + ReportTransactionSent(mojom::CoinType::ETH, false); + ReportTransactionSent(mojom::CoinType::FIL, false); + ReportTransactionSent(mojom::CoinType::SOL, false); +} + void BraveWalletP3A::ReportEthereumProvider( mojom::EthereumProviderType provider_type) { UMA_HISTOGRAM_ENUMERATION(kEthProviderHistogramName, provider_type); @@ -89,6 +105,46 @@ void BraveWalletP3A::ReportOnboardingAction( onboarding_action); } +void BraveWalletP3A::ReportTransactionSent(mojom::CoinType coin, + bool new_send) { + DictionaryPrefUpdate last_sent_time_update( + pref_service_, kBraveWalletLastTransactionSentTimeDict); + base::Value::Dict& last_sent_time_dict = last_sent_time_update->GetDict(); + + std::string coin_key = base::NumberToString(static_cast(coin)); + + base::Time now = base::Time::Now(); + base::Time last_sent_time = base::Time::FromDoubleT( + last_sent_time_dict.FindDouble(coin_key).value_or(0.0)); + + if (!new_send && last_sent_time.is_null()) { + // Don't report if a transaction was never sent. + return; + } + int answer = 0; + if (new_send || (now - last_sent_time) < base::Days(7)) { + answer = 1; + } + if (new_send) { + last_sent_time_dict.Set(coin_key, now.ToDoubleT()); + } + + const char* histogram_name; + switch (coin) { + case mojom::CoinType::ETH: + histogram_name = kEthTransactionSentHistogramName; + break; + case mojom::CoinType::SOL: + histogram_name = kSolTransactionSentHistogramName; + break; + case mojom::CoinType::FIL: + histogram_name = kFilTransactionSentHistogramName; + break; + } + + base::UmaHistogramExactLinear(histogram_name, answer, 2); +} + void BraveWalletP3A::RecordInitialBraveWalletP3AState() { keyring_service_->GetKeyringInfo(mojom::kDefaultKeyringId, base::BindOnce(&RecordKeyringCreated)); diff --git a/components/brave_wallet/browser/brave_wallet_p3a.h b/components/brave_wallet/browser/brave_wallet_p3a.h index a267be1a5f4e..a9fb45d3755d 100644 --- a/components/brave_wallet/browser/brave_wallet_p3a.h +++ b/components/brave_wallet/browser/brave_wallet_p3a.h @@ -22,6 +22,9 @@ extern const char kDefaultSolanaWalletHistogramName[]; extern const char kKeyringCreatedHistogramName[]; extern const char kOnboardingConversionHistogramName[]; extern const char kEthProviderHistogramName[]; +extern const char kEthTransactionSentHistogramName[]; +extern const char kSolTransactionSentHistogramName[]; +extern const char kFilTransactionSentHistogramName[]; class BraveWalletService; class KeyringService; @@ -42,10 +45,13 @@ class BraveWalletP3A : public mojom::BraveWalletServiceObserver, mojo::PendingRemote MakeRemote(); void Bind(mojo::PendingReceiver receiver); + void Update(); + void ReportEthereumProvider( mojom::EthereumProviderType provider_type) override; void ReportOnboardingAction( mojom::OnboardingAction onboarding_action) override; + void ReportTransactionSent(mojom::CoinType coin, bool new_send) override; // KeyringServiceObserver void KeyringCreated(const std::string& keyring_id) override; diff --git a/components/brave_wallet/browser/brave_wallet_p3a_private.cc b/components/brave_wallet/browser/brave_wallet_p3a_private.cc index 534a93e3d58b..46f00063e45b 100644 --- a/components/brave_wallet/browser/brave_wallet_p3a_private.cc +++ b/components/brave_wallet/browser/brave_wallet_p3a_private.cc @@ -13,4 +13,7 @@ void BraveWalletP3APrivate::ReportEthereumProvider( void BraveWalletP3APrivate::ReportOnboardingAction( mojom::OnboardingAction onboarding_action) {} +void BraveWalletP3APrivate::ReportTransactionSent(mojom::CoinType coin, + bool new_send) {} + } // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_p3a_private.h b/components/brave_wallet/browser/brave_wallet_p3a_private.h index d55edd325093..13d0e9e08ced 100644 --- a/components/brave_wallet/browser/brave_wallet_p3a_private.h +++ b/components/brave_wallet/browser/brave_wallet_p3a_private.h @@ -18,6 +18,7 @@ class BraveWalletP3APrivate : public mojom::BraveWalletP3A { mojom::EthereumProviderType provider_type) override; void ReportOnboardingAction( mojom::OnboardingAction onboarding_action) override; + void ReportTransactionSent(mojom::CoinType coin, bool new_send) override; }; } // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_prefs.cc b/components/brave_wallet/browser/brave_wallet_prefs.cc index f453213bb401..ea07dad34a68 100644 --- a/components/brave_wallet/browser/brave_wallet_prefs.cc +++ b/components/brave_wallet/browser/brave_wallet_prefs.cc @@ -84,6 +84,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { p3a_utils::RegisterFeatureUsagePrefs(registry, kBraveWalletP3AFirstUnlockTime, kBraveWalletP3ALastUnlockTime, kBraveWalletP3AUsedSecondDay, nullptr); + registry->RegisterDictionaryPref(kBraveWalletLastTransactionSentTimeDict); } void RegisterProfilePrefsForMigration( diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index 802f4eaf0e3f..ac981d9b810d 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -861,6 +861,7 @@ base::Value::Dict BraveWalletService::GetDefaultFilecoinAssets() { void BraveWalletService::OnP3ATimerFired() { RecordWalletUsage(false); + brave_wallet_p3a_.Update(); } void BraveWalletService::OnWalletUnlockPreferenceChanged( diff --git a/components/brave_wallet/browser/pref_names.cc b/components/brave_wallet/browser/pref_names.cc index ea364bfdbcae..7a378cc89d60 100644 --- a/components/brave_wallet/browser/pref_names.cc +++ b/components/brave_wallet/browser/pref_names.cc @@ -49,6 +49,8 @@ extern const char kBraveWalletP3AUsedSecondDay[] = "brave.wallet.p3a_used_second_day"; const char kBraveWalletKeyringEncryptionKeysMigrated[] = "brave.wallet.keyring_encryption_keys_migrated"; +const char kBraveWalletLastTransactionSentTimeDict[] = + "brave.wallet.last_transaction_sent_time_dict"; // DEPRECATED const char kBraveWalletSelectedAccount[] = "brave.wallet.selected_account"; diff --git a/components/brave_wallet/browser/pref_names.h b/components/brave_wallet/browser/pref_names.h index 943d4b214243..c201a55ad9f5 100644 --- a/components/brave_wallet/browser/pref_names.h +++ b/components/brave_wallet/browser/pref_names.h @@ -43,6 +43,8 @@ extern const char kBraveWalletP3AUsedSecondDay[]; extern const char kBraveWalletKeyringEncryptionKeysMigrated[]; +extern const char kBraveWalletLastTransactionSentTimeDict[]; + // DEPRECATED extern const char kBraveWalletSelectedAccount[]; extern const char kBraveWalletWeb3ProviderDeprecated[]; diff --git a/components/brave_wallet/common/brave_wallet.mojom b/components/brave_wallet/common/brave_wallet.mojom index 04c6f6bbe1d5..0e452891b9f3 100644 --- a/components/brave_wallet/common/brave_wallet.mojom +++ b/components/brave_wallet/common/brave_wallet.mojom @@ -223,7 +223,8 @@ interface PanelHandlerFactory { pending_receiver eth_tx_manager_proxy, pending_receiver solana_tx_manager_proxy, pending_receiver fil_tx_manager_proxy, - pending_receiver brave_wallet_service); + pending_receiver brave_wallet_service, + pending_receiver brave_wallet_p3a); }; interface PageHandlerFactory { @@ -408,6 +409,9 @@ const string kFilecoinTestnetKeyringId = "filecoin_testnet"; const string kSolanaKeyringId = "solana"; const string kDefaultKeyringId = "default"; +const string kP3ACountTestNetworksSwitch = "p3a-count-wallet-test-networks"; +const string kP3ACountTestNetworksLoadTimeKey = "braveWalletP3ACountTestNetworks"; + enum FilecoinAddressProtocol { SECP256K1 = 1, // Represents the address SECP256K1 protocol BLS = 3 // Represents the address BLS protocol @@ -1321,6 +1325,9 @@ interface BraveWalletP3A { // Called when a Wallet onboarding action is performed. ReportOnboardingAction(OnboardingAction onboarding_action); + + // Called when a mainnet transaction is sent. + ReportTransactionSent(CoinType coin, bool new_send); }; enum OnboardingAction { diff --git a/components/brave_wallet_ui/common/async/handlers.ts b/components/brave_wallet_ui/common/async/handlers.ts index f9d22ebbae3e..e111141b213c 100644 --- a/components/brave_wallet_ui/common/async/handlers.ts +++ b/components/brave_wallet_ui/common/async/handlers.ts @@ -59,7 +59,7 @@ import { import { Store } from './types' import InteractionNotifier from './interactionNotifier' import { getCoinFromTxDataUnion, getNetworkInfo } from '../../utils/network-utils' -import { isSolanaTransaction } from '../../utils/tx-utils' +import { isSolanaTransaction, shouldReportTransactionP3A } from '../../utils/tx-utils' const handler = new AsyncActionHandler() @@ -435,9 +435,9 @@ handler.on(WalletActions.approveERC20Allowance.type, async (store: Store, payloa }) handler.on(WalletActions.approveTransaction.type, async (store: Store, txInfo: BraveWallet.TransactionInfo) => { - const apiProxy = getAPIProxy() + const { txService, braveWalletP3A } = getAPIProxy() const coin = getCoinFromTxDataUnion(txInfo.txDataUnion) - const result = await apiProxy.txService.approveTransaction(coin, txInfo.id) + const result = await txService.approveTransaction(coin, txInfo.id) const error = result.errorUnion.providerError ?? result.errorUnion.solanaProviderError if (error !== BraveWallet.ProviderError.kSuccess) { await store.dispatch(WalletActions.setTransactionProviderError({ @@ -447,6 +447,11 @@ handler.on(WalletActions.approveTransaction.type, async (store: Store, txInfo: B message: result.errorMessage } as TransactionProviderError })) + } else { + const { selectedNetwork } = getWalletState(store) + if (shouldReportTransactionP3A(txInfo, selectedNetwork, coin)) { + braveWalletP3A.reportTransactionSent(coin, true) + } } await store.dispatch(refreshTransactionHistory(txInfo.fromAddress)) diff --git a/components/brave_wallet_ui/constants/types.ts b/components/brave_wallet_ui/constants/types.ts index 7581d8ac61a2..2846d5d73355 100644 --- a/components/brave_wallet_ui/constants/types.ts +++ b/components/brave_wallet_ui/constants/types.ts @@ -841,3 +841,11 @@ export interface AccountButtonOptionsObjectType { } export type StringWithAutocomplete = T | (string & Record) + +export const P3ASendTransactionTypes = [ + BraveWallet.TransactionType.ETHSend, + BraveWallet.TransactionType.ERC20Transfer, + BraveWallet.TransactionType.SolanaSystemTransfer, + BraveWallet.TransactionType.SolanaSPLTokenTransfer, + BraveWallet.TransactionType.SolanaSPLTokenTransferWithAssociatedTokenAccountCreation +] diff --git a/components/brave_wallet_ui/panel/wallet_panel_api_proxy.ts b/components/brave_wallet_ui/panel/wallet_panel_api_proxy.ts index 64edeff39f85..d5bebb680ec6 100644 --- a/components/brave_wallet_ui/panel/wallet_panel_api_proxy.ts +++ b/components/brave_wallet_ui/panel/wallet_panel_api_proxy.ts @@ -27,7 +27,8 @@ class WalletPanelApiProxy extends WalletApiProxy { this.ethTxManagerProxy.$.bindNewPipeAndPassReceiver(), this.solanaTxManagerProxy.$.bindNewPipeAndPassReceiver(), this.filTxManagerProxy.$.bindNewPipeAndPassReceiver(), - this.braveWalletService.$.bindNewPipeAndPassReceiver()) + this.braveWalletService.$.bindNewPipeAndPassReceiver(), + this.braveWalletP3A.$.bindNewPipeAndPassReceiver()) } } diff --git a/components/brave_wallet_ui/utils/tx-utils.ts b/components/brave_wallet_ui/utils/tx-utils.ts index c8e2341fc804..02680efb8625 100644 --- a/components/brave_wallet_ui/utils/tx-utils.ts +++ b/components/brave_wallet_ui/utils/tx-utils.ts @@ -1,6 +1,7 @@ -import { BraveWallet } from '../constants/types' +import { BraveWallet, P3ASendTransactionTypes, SupportedTestNetworks } from '../constants/types' import { getLocale } from '../../common/locale' import { SolanaTransactionTypes } from '../common/constants/solana' +import { loadTimeData } from '../../common/loadTimeData' type Order = 'ascending' | 'descending' @@ -38,3 +39,12 @@ export function isSolanaTransaction (transaction: BraveWallet.TransactionInfo) { return SolanaTransactionTypes.includes(txType) || (txType === BraveWallet.TransactionType.Other && solanaTxData !== undefined) } + +export function shouldReportTransactionP3A (txInfo: BraveWallet.TransactionInfo, network: BraveWallet.NetworkInfo, coin: BraveWallet.CoinType) { + if (P3ASendTransactionTypes.includes(txInfo.txType) || + (coin === BraveWallet.CoinType.FIL && txInfo.txType === BraveWallet.TransactionType.Other)) { + const countTestNetworks = loadTimeData.getBoolean(BraveWallet.P3A_COUNT_TEST_NETWORKS_LOAD_TIME_KEY) + return countTestNetworks || !SupportedTestNetworks.includes(network.chainId) + } + return false +} diff --git a/components/p3a/metric_names.h b/components/p3a/metric_names.h index 03e928222a2f..cb57ca4acc93 100644 --- a/components/p3a/metric_names.h +++ b/components/p3a/metric_names.h @@ -82,11 +82,14 @@ constexpr inline auto kCollectedTypicalHistograms = "Brave.VPN.DaysInMonthUsed", "Brave.VPN.LastUsageTime", "Brave.Wallet.EthProvider", + "Brave.Wallet.EthTransactionSent", + "Brave.Wallet.FilTransactionSent", "Brave.Wallet.DefaultSolanaWalletSetting", "Brave.Wallet.DefaultWalletSetting", "Brave.Wallet.KeyringCreated", "Brave.Wallet.NewUserReturning", "Brave.Wallet.OnboardingConversion.2", + "Brave.Wallet.SolTransactionSent", "Brave.Wallet.UsageDaysInWeek", "Brave.Wallet.UsageMonthly.2", "Brave.Welcome.InteractionStatus",