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

feat(wallet): Refactor network selector for multi chain #16355

Merged
merged 2 commits into from
Dec 14, 2022
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
4 changes: 4 additions & 0 deletions android/brave_java_sources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/app/domain/DappsModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/KeyringModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/NetworkModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/NetworkSelectorModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/SendModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/SwapModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/WalletModel.java",
Expand Down Expand Up @@ -145,6 +146,7 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BravePermissionAccountsListAdapter.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/presenters/Amount.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/presenters/NetworkInfoPresenter.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/presenters/SolanaInstructionPresenter.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/AccountsPermissionsHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/AddressUtils.java",
Expand All @@ -155,9 +157,11 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/BalanceHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/Blockies.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/ItemOffsetDecoration.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/JavaUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/KeystoreHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/NavigationItem.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/NetworkResponsesCollector.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/NetworkUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/ParsedTransaction.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/ParsedTransactionFees.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/PendingTxHelper.java",
Expand Down
10 changes: 10 additions & 0 deletions android/java/org/chromium/chrome/browser/app/BraveActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package org.chromium.chrome.browser.app;

import static org.chromium.chrome.browser.app.domain.NetworkSelectorModel.Mode.DEFAULT_WALLET_NETWORK;
import static org.chromium.chrome.browser.crypto_wallet.activities.NetworkSelectorActivity.NETWORK_SELECTOR_MODE;
import static org.chromium.ui.base.ViewUtils.dpToPx;

import android.annotation.SuppressLint;
Expand Down Expand Up @@ -92,6 +94,7 @@
import org.chromium.chrome.browser.DormantUsersEngagementDialogFragment;
import org.chromium.chrome.browser.InternetConnection;
import org.chromium.chrome.browser.LaunchIntentDispatcher;
import org.chromium.chrome.browser.app.domain.NetworkSelectorModel;
import org.chromium.chrome.browser.app.domain.WalletModel;
import org.chromium.chrome.browser.bookmarks.TabBookmarker;
import org.chromium.chrome.browser.brave_news.models.FeedItemsCard;
Expand Down Expand Up @@ -1227,8 +1230,15 @@ public void viewOnBlockExplorer(String address, @CoinType.EnumType int coinType)

// should only be called if the wallet is setup and unlocked
public void openNetworkSelection() {
openNetworkSelection(DEFAULT_WALLET_NETWORK);
}

// should only be called if the wallet is setup and unlocked
public void openNetworkSelection(NetworkSelectorModel.Mode mode) {
Intent braveNetworkSelectionIntent = new Intent(this, NetworkSelectorActivity.class);
braveNetworkSelectionIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
// Either in global or local network selection mode
braveNetworkSelectionIntent.putExtra(NETWORK_SELECTOR_MODE, mode);
startActivity(braveNetworkSelectionIntent);
}

Expand Down
111 changes: 98 additions & 13 deletions android/java/org/chromium/chrome/browser/app/domain/NetworkModel.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

package org.chromium.chrome.browser.app.domain;

import android.content.Context;
Expand All @@ -17,13 +22,16 @@
import org.chromium.brave_wallet.mojom.NetworkInfo;
import org.chromium.chrome.browser.crypto_wallet.activities.BuySendSwapActivity;
import org.chromium.chrome.browser.crypto_wallet.model.CryptoAccountTypeInfo;
import org.chromium.chrome.browser.crypto_wallet.util.JavaUtils;
import org.chromium.chrome.browser.crypto_wallet.util.NetworkResponsesCollector;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
import org.chromium.chrome.browser.crypto_wallet.util.WalletConstants;
import org.chromium.chrome.browser.util.Triple;
import org.chromium.mojo.bindings.Callbacks;
import org.chromium.mojo.system.MojoException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class NetworkModel implements JsonRpcServiceObserver {
Expand All @@ -41,6 +49,9 @@ public class NetworkModel implements JsonRpcServiceObserver {
_mChainNetworkAllNetwork;
private final Context mContext;
private final MediatorLiveData<String[]> _mCustomNetworkIds;
private final MediatorLiveData<List<NetworkInfo>> _mPrimaryNetworks;
private final MediatorLiveData<List<NetworkInfo>> _mSecondaryNetworks;
private NetworkSelectorModel mNetworkSelectorModel;
public final LiveData<String[]> mCustomNetworkIds;
public LiveData<NetworkInfo> mNeedToCreateAccountForNetwork;
public final LiveData<Triple<String, NetworkInfo, NetworkInfo[]>> mChainNetworkAllNetwork;
Expand All @@ -49,6 +60,8 @@ public class NetworkModel implements JsonRpcServiceObserver {
public final LiveData<NetworkInfo[]> mDefaultCoinCryptoNetworks;
public final LiveData<NetworkInfo[]> mCryptoNetworks;
public final LiveData<NetworkInfo> mDefaultNetwork;
public final LiveData<List<NetworkInfo>> mPrimaryNetworks;
public final LiveData<List<NetworkInfo>> mSecondaryNetworks;

public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
CryptoSharedActions cryptoSharedActions, Context context) {
Expand All @@ -74,7 +87,12 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
_mCustomNetworkIds = new MediatorLiveData<>();
_mCustomNetworkIds.postValue(new String[0]);
mCustomNetworkIds = _mCustomNetworkIds;
_mPrimaryNetworks = new MediatorLiveData<>();
mPrimaryNetworks = _mPrimaryNetworks;
_mSecondaryNetworks = new MediatorLiveData<>();
mSecondaryNetworks = _mSecondaryNetworks;
jsonRpcService.addObserver(this);
mNetworkSelectorModel = new NetworkSelectorModel(this, mContext);
_mPairChainAndNetwork.setValue(Pair.create("", new NetworkInfo[] {}));
_mPairChainAndNetwork.addSource(_mChainId, chainId -> {
_mPairChainAndNetwork.setValue(
Expand Down Expand Up @@ -124,6 +142,38 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
mJsonRpcService.getCustomNetworks(
coinType, customNetworks -> { _mCustomNetworkIds.postValue(customNetworks); });
});
_mPrimaryNetworks.addSource(mCryptoNetworks, networkInfos -> {
List<NetworkInfo> primaryNws = new ArrayList<>();
for (NetworkInfo networkInfo : networkInfos) {
if (WalletConstants.SUPPORTED_TOP_LEVEL_CHAIN_IDS.contains(networkInfo.chainId)) {
primaryNws.add(networkInfo);
}
}
_mPrimaryNetworks.postValue(primaryNws);
});
_mSecondaryNetworks.addSource(mCryptoNetworks, networkInfos -> {
List<NetworkInfo> primaryNws = new ArrayList<>();
for (NetworkInfo networkInfo : networkInfos) {
if (!WalletConstants.SUPPORTED_TOP_LEVEL_CHAIN_IDS.contains(networkInfo.chainId)
&& !WalletConstants.KNOWN_TEST_CHAIN_IDS.contains(networkInfo.chainId)) {
primaryNws.add(networkInfo);
}
}
_mSecondaryNetworks.postValue(primaryNws);
});
}

/**
* Create a network model to handle default wallet network selector events
* @return mNetworkSelectorModel object in DEFAULT_WALLET_NETWORK mode
*/
public NetworkSelectorModel openNetworkSelectorModel() {
return openNetworkSelectorModel(NetworkSelectorModel.Mode.DEFAULT_WALLET_NETWORK);
}

public NetworkSelectorModel openNetworkSelectorModel(NetworkSelectorModel.Mode mode) {
mNetworkSelectorModel.updateSelectorMode(mode);
return mNetworkSelectorModel;
}

public void setAccountInfosFromKeyRingModel(
Expand Down Expand Up @@ -176,19 +226,9 @@ public void init() {

public void setNetworkWithAccountCheck(
NetworkInfo networkToBeSetAsSelected, Callbacks.Callback1<Boolean> callback) {
List<AccountInfo> accountInfos = mSharedData.getAccounts().getValue();
boolean hasAccountOfNetworkType = false;
for (AccountInfo accountInfo : accountInfos) {
hasAccountOfNetworkType = accountInfo.coin == networkToBeSetAsSelected.coin;
if (hasAccountOfNetworkType) {
break;
}
}
NetworkInfo selectedNetwork = _mDefaultNetwork.getValue();
if (selectedNetwork != null
&& selectedNetwork.chainId.equals(networkToBeSetAsSelected.chainId)
&& selectedNetwork.coin == networkToBeSetAsSelected.coin)
return;
if (isSameNetwork(networkToBeSetAsSelected, selectedNetwork)) return;
boolean hasAccountOfNetworkType = hasAccountOfNetworkType(networkToBeSetAsSelected);
if (hasAccountOfNetworkType) {
mJsonRpcService.setNetwork(
networkToBeSetAsSelected.chainId, networkToBeSetAsSelected.coin, isSelected -> {
Expand Down Expand Up @@ -245,10 +285,55 @@ private NetworkInfo[] stripDebugNetwork(Context context, NetworkInfo[] networkIn
networkInfosFiltered.add(networkInfo);
}
}
return networkInfosFiltered.toArray(new NetworkInfo[networkInfosFiltered.size()]);
return networkInfosFiltered.toArray(new NetworkInfo[0]);
}
}

List<NetworkInfo> getSubTestNetworks(NetworkInfo networkInfo) {
NetworkInfo[] cryptoNws = _mCryptoNetworks.getValue();
if (cryptoNws == null || cryptoNws.length == 0
|| !WalletConstants.SUPPORTED_TOP_LEVEL_CHAIN_IDS.contains(networkInfo.chainId))
return Collections.emptyList();
List<NetworkInfo> list = new ArrayList<>();
for (NetworkInfo info : cryptoNws) {
if (WalletConstants.KNOWN_TEST_CHAIN_IDS.contains(info.chainId)
&& networkInfo.coin == info.coin && networkInfo.symbol.equals(info.symbol)
&& !isCustomChain(info.chainId)) {
list.add(info);
}
}
return list;
}

private boolean isCustomChain(String netWorkChainId) {
String[] customNetworkChains = JavaUtils.safeVal(_mCustomNetworkIds.getValue());
for (String chain : customNetworkChains) {
if (chain.equals(netWorkChainId)) {
return true;
}
}
return false;
}

boolean hasAccountOfNetworkType(NetworkInfo networkToBeSetAsSelected) {
List<AccountInfo> accountInfos = mSharedData.getAccounts().getValue();
boolean hasAccountOfNetworkType = false;
for (AccountInfo accountInfo : accountInfos) {
hasAccountOfNetworkType = accountInfo.coin == networkToBeSetAsSelected.coin;
if (hasAccountOfNetworkType) {
break;
}
}
return hasAccountOfNetworkType;
}

private boolean isSameNetwork(
NetworkInfo networkToBeSetAsSelected, NetworkInfo selectedNetwork) {
return selectedNetwork != null
&& selectedNetwork.chainId.equals(networkToBeSetAsSelected.chainId)
&& selectedNetwork.coin == networkToBeSetAsSelected.coin;
}

@Override
public void chainChangedEvent(String chainId, int coin) {
_mChainId.postValue(chainId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

package org.chromium.chrome.browser.app.domain;

import android.content.Context;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;

import org.chromium.brave_wallet.mojom.NetworkInfo;
import org.chromium.chrome.browser.crypto_wallet.presenters.NetworkInfoPresenter;
import org.chromium.chrome.browser.crypto_wallet.util.NetworkUtils;
import org.chromium.mojo.bindings.Callbacks;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* NetworkSelectorModel handles the selector of network for either global or local network
* selection.
* {@link NetworkSelectorModel#mMode} acts as a switch between global or local network selection
* live data events. Local selection can be observed via {@link
* NetworkSelectorModel#mSelectedNetwork} and global via {@link NetworkModel#mDefaultNetwork}
*/
public class NetworkSelectorModel {
private final Context mContext;
private final NetworkModel mNetworkModel;
private final MutableLiveData<NetworkInfo> _mLocalSelectedNetwork;
private Mode mMode;
public LiveData<List<NetworkInfoPresenter>> mPrimaryNetworks;
public LiveData<List<NetworkInfoPresenter>> mSecondaryNetworks;
public final LiveData<NetworkInfo> mSelectedNetwork;

public NetworkSelectorModel(Mode mode, NetworkModel networkModel, Context context) {
mMode = mode;
if (mMode == null) {
mMode = Mode.LOCAL_NETWORK_FILTER;
}
mNetworkModel = networkModel;
mContext = context;
_mLocalSelectedNetwork = new MutableLiveData<>();
mSelectedNetwork = _mLocalSelectedNetwork;
init();
}

public NetworkSelectorModel(NetworkModel networkModel, Context context) {
this(Mode.DEFAULT_WALLET_NETWORK, networkModel, context);
}

public void init() {
if (mMode == Mode.DEFAULT_WALLET_NETWORK) {
_mLocalSelectedNetwork.postValue(mNetworkModel.mDefaultNetwork.getValue());
} else if (mMode == Mode.LOCAL_NETWORK_FILTER) {
_mLocalSelectedNetwork.postValue(NetworkUtils.getAllNetworkOption(mContext));
}
mPrimaryNetworks = Transformations.map(mNetworkModel.mPrimaryNetworks, networkInfos -> {
List<NetworkInfoPresenter> list = new ArrayList<>();
if (mMode == Mode.LOCAL_NETWORK_FILTER) {
list.add(0,
new NetworkInfoPresenter(NetworkUtils.getAllNetworkOption(mContext), true,
Collections.emptyList()));
}
for (NetworkInfo networkInfo : networkInfos) {
list.add(new NetworkInfoPresenter(
networkInfo, true, mNetworkModel.getSubTestNetworks(networkInfo)));
}
return list;
});
mSecondaryNetworks = Transformations.map(mNetworkModel.mSecondaryNetworks, networkInfos -> {
List<NetworkInfoPresenter> list = new ArrayList<>();
for (NetworkInfo networkInfo : networkInfos) {
list.add(new NetworkInfoPresenter(networkInfo, false, Collections.emptyList()));
}
return list;
});
}

/**
* Reset the mode
* DEFAULT_WALLET_NETWORK for global wallet network
* LOCAL_NETWORK_FILTER for only onscreen network selection via "mSelectedNetwork"
* @param mode to set selected network
*/
public void updateSelectorMode(Mode mode) {
this.mMode = mode;
init();
}

public void setNetworkWithAccountCheck(
NetworkInfo networkToBeSetAsSelected, Callbacks.Callback1<Boolean> callback) {
boolean hasAccountOfNetworkType =
mNetworkModel.hasAccountOfNetworkType(networkToBeSetAsSelected);
if (!hasAccountOfNetworkType && mMode == Mode.DEFAULT_WALLET_NETWORK) {
// Delegate to network model to handle account creation flow
mNetworkModel.setNetworkWithAccountCheck(networkToBeSetAsSelected, isSet -> {
callback.call(isSet);
if (isSet) {
_mLocalSelectedNetwork.postValue(networkToBeSetAsSelected);
}
});
return;
}
if (mMode == Mode.LOCAL_NETWORK_FILTER) {
_mLocalSelectedNetwork.postValue(networkToBeSetAsSelected);
callback.call(true);
}
}

public enum Mode { DEFAULT_WALLET_NETWORK, LOCAL_NETWORK_FILTER }
}
Loading