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

Wallet address resolution for Android #16423

Merged
merged 2 commits into from
Dec 21, 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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import com.google.android.gms.vision.barcode.BarcodeDetector;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;

import org.chromium.base.BraveFeatureList;
import org.chromium.base.Log;
import org.chromium.brave_wallet.mojom.AccountInfo;
import org.chromium.brave_wallet.mojom.BlockchainToken;
Expand Down Expand Up @@ -83,7 +84,9 @@
import org.chromium.chrome.browser.crypto_wallet.util.TokenUtils;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
import org.chromium.chrome.browser.crypto_wallet.util.Validations;
import org.chromium.chrome.browser.crypto_wallet.util.WalletNativeUtils;
import org.chromium.chrome.browser.crypto_wallet.util.WalletUtils;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.qrreader.BarcodeTracker;
import org.chromium.chrome.browser.qrreader.BarcodeTrackerFactory;
import org.chromium.chrome.browser.qrreader.CameraSource;
Expand Down Expand Up @@ -169,6 +172,7 @@ public int getValue() {
private EditText mFromValueText;
private EditText mToValueText;
private EditText mSendToAddrText;
private TextView mResolvedAddrText;
private TextView mMarketPriceValueText;
private TextView mFromBalanceText;
private TextView mToBalanceText;
Expand Down Expand Up @@ -759,6 +763,8 @@ private void adjustControls() {
toleranceSection.setVisibility(View.GONE);
}

mResolvedAddrText = findViewById(R.id.resolved_addr_text);

// Individual
if (mActivityType == ActivityType.BUY) {
TextView fromBuyText = findViewById(R.id.from_buy_text);
Expand Down Expand Up @@ -919,6 +925,10 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
String value = mFromValueText.getText().toString();
if (mActivityType == ActivityType.SEND) {
String to = mSendToAddrText.getText().toString();
if (!mResolvedAddrText.getText().toString().isEmpty()) {
to = mResolvedAddrText.getText().toString();
}

if (to.isEmpty()) {
return;
}
Expand Down Expand Up @@ -1176,6 +1186,59 @@ public void onBackPressed() {
super.onBackPressed();
}

private void onResolveWalletAddressDone(String domain, String result) {
if (!domain.equals(mSendToAddrText.getText().toString())) {
return;
}

if (result == null || result.isEmpty()) {
mResolvedAddrText.setVisibility(View.GONE);
mResolvedAddrText.setText("");
String notRegisteredErrorText = String.format(
getString(R.string.wallet_domain_not_registered_error_text), domain);

setSendToFromValueValidationResult(notRegisteredErrorText, true, true);
} else {
mResolvedAddrText.setVisibility(View.VISIBLE);
mResolvedAddrText.setText(result);
setSendToFromValueValidationResult("", false, true);
}
}

private boolean maybeResolveWalletAddress() {
String domain = mSendToAddrText.getText().toString();

if (WalletNativeUtils.isUnstoppableDomainsTld(domain)) {
mJsonRpcService.unstoppableDomainsGetWalletAddr(
domain, mCurrentBlockchainToken, (response, errorResponse, errorString) -> {
onResolveWalletAddressDone(domain, response);
});
return true;
}

if (mCurrentBlockchainToken.coin == CoinType.ETH && WalletNativeUtils.isEnsTld(domain)) {
mJsonRpcService.ensGetEthAddr(domain, null,
(response, requireOffchainConsent, errorResponse, errorString) -> {
onResolveWalletAddressDone(domain, response);
});
return true;
}

if (ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_WALLET_SNS)) {
if (mCurrentBlockchainToken.coin == CoinType.SOL
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be combined to a single if

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is supposed to be a temporary feature and to be removed as soon as our backend is ready. While inner if block matches pattern above

&& WalletNativeUtils.isSnsTld(domain)) {
mJsonRpcService.snsGetSolAddr(domain, (response, errorResponse, errorString) -> {
onResolveWalletAddressDone(domain, response);
});
return true;
}
}

mResolvedAddrText.setVisibility(View.GONE);
mResolvedAddrText.setText("");
return false;
}
Comment on lines +1211 to +1240
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually will be refactored to a single mojo call brave/brave-browser#26655


private TextWatcher getTextWatcherFromToValueText(boolean from) {
return new FilterTextFromToValueText(from);
}
Expand Down Expand Up @@ -1210,6 +1273,8 @@ public FilterTextWatcherSendToAddr() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (maybeResolveWalletAddress()) return;

String fromAccountAddress = mCustomAccountAdapter.getAccountAddressAtPosition(
mAccountSpinner.getSelectedItemPosition());

Expand Down Expand Up @@ -1237,6 +1302,8 @@ public OnFocusChangeListenerToSend() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
if (maybeResolveWalletAddress()) return;

String fromAccountAddress = mCustomAccountAdapter.getAccountAddressAtPosition(
mAccountSpinner.getSelectedItemPosition());
String receiverAccountAddress = ((EditText) v).getText().toString();
Expand Down Expand Up @@ -1459,6 +1526,10 @@ token.symbol, getResources().getDisplayMetrics().density, assetText, this, true,
enableDisableSwapButton();
getSendSwapQuota(true, false);
}

if (mActivityType == ActivityType.SEND) {
maybeResolveWalletAddress();
}
}

private void enableDisableSwapButton() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,23 @@ public static void resetWallet(Profile profile) {
WalletNativeUtilsJni.get().resetWallet(profile);
}

public static boolean isUnstoppableDomainsTld(String domain) {
return WalletNativeUtilsJni.get().isUnstoppableDomainsTld(domain);
}

public static boolean isEnsTld(String domain) {
return WalletNativeUtilsJni.get().isEnsTld(domain);
}

public static boolean isSnsTld(String domain) {
return WalletNativeUtilsJni.get().isSnsTld(domain);
}

@NativeMethods
interface Natives {
void resetWallet(Profile profile);
boolean isUnstoppableDomainsTld(String domain);
boolean isEnsTld(String domain);
boolean isSnsTld(String domain);
}
}
10 changes: 10 additions & 0 deletions android/java/res/layout/activity_buy_send_swap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,16 @@

</LinearLayout>

<TextView
android:id="@+id/resolved_addr_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"
android:textColor="@color/wallet_text_color"
android:textIsSelectable="true"
android:textSize="12sp"
android:visibility="gone"/>

<TextView
android:id="@+id/to_send_error_text"
android:layout_width="wrap_content"
Expand Down
26 changes: 26 additions & 0 deletions browser/brave_wallet/android/wallet_native_utils_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/logging.h"
#include "brave/browser/brave_wallet/brave_wallet_service_factory.h"
#include "brave/build/android/jni_headers/WalletNativeUtils_jni.h"
#include "brave/components/brave_wallet/browser/brave_wallet_service.h"
#include "brave/components/decentralized_dns/core/utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"

Expand All @@ -26,5 +28,29 @@ static void JNI_WalletNativeUtils_ResetWallet(
brave_wallet_service->Reset();
}

static jboolean JNI_WalletNativeUtils_IsUnstoppableDomainsTld(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& domain) {
auto domain_string = base::android::ConvertJavaStringToUTF8(env, domain);

return decentralized_dns::IsUnstoppableDomainsTLD(domain_string);
}

static jboolean JNI_WalletNativeUtils_IsEnsTld(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& domain) {
auto domain_string = base::android::ConvertJavaStringToUTF8(env, domain);

return decentralized_dns::IsENSTLD(domain_string);
}

static jboolean JNI_WalletNativeUtils_IsSnsTld(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& domain) {
auto domain_string = base::android::ConvertJavaStringToUTF8(env, domain);

return decentralized_dns::IsSnsTLD(domain_string);
}

} // namespace android
} // namespace chrome
39 changes: 23 additions & 16 deletions browser/decentralized_dns/test/utils_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ class UtilsUnitTest : public testing::Test {
};

TEST_F(UtilsUnitTest, IsUnstoppableDomainsTLD) {
EXPECT_TRUE(IsUnstoppableDomainsTLD(GURL("http://test.crypto")));
EXPECT_FALSE(IsUnstoppableDomainsTLD(GURL("http://test.com")));
EXPECT_FALSE(IsUnstoppableDomainsTLD(GURL("http://test.eth")));
EXPECT_FALSE(IsUnstoppableDomainsTLD(GURL("http://crypto")));
EXPECT_TRUE(IsUnstoppableDomainsTLD("test.crypto"));
EXPECT_FALSE(IsUnstoppableDomainsTLD("test.com"));
EXPECT_FALSE(IsUnstoppableDomainsTLD("test.eth"));
EXPECT_FALSE(IsUnstoppableDomainsTLD("crypto"));
}

TEST_F(UtilsUnitTest, IsUnstoppableDomainsResolveMethodAsk) {
Expand All @@ -42,19 +42,26 @@ TEST_F(UtilsUnitTest, IsUnstoppableDomainsResolveMethodAsk) {
EXPECT_FALSE(IsUnstoppableDomainsResolveMethodAsk(local_state()));
}

TEST_F(UtilsUnitTest, IsUnstoppableDomainsResolveMethodEthereum) {
EXPECT_FALSE(IsUnstoppableDomainsResolveMethodEthereum(local_state()));
TEST_F(UtilsUnitTest, IsUnstoppableDomainsResolveMethodEnabled) {
EXPECT_FALSE(IsUnstoppableDomainsResolveMethodEnabled(local_state()));

local_state()->SetInteger(kUnstoppableDomainsResolveMethod,
static_cast<int>(ResolveMethodTypes::ENABLED));
EXPECT_TRUE(IsUnstoppableDomainsResolveMethodEthereum(local_state()));
EXPECT_TRUE(IsUnstoppableDomainsResolveMethodEnabled(local_state()));
}

TEST_F(UtilsUnitTest, IsENSTLD) {
EXPECT_TRUE(IsENSTLD(GURL("http://test.eth")));
EXPECT_FALSE(IsENSTLD(GURL("http://test.com")));
EXPECT_FALSE(IsENSTLD(GURL("http://test.crypto")));
EXPECT_FALSE(IsENSTLD(GURL("http://eth")));
EXPECT_TRUE(IsENSTLD("test.eth"));
EXPECT_FALSE(IsENSTLD("test.com"));
EXPECT_FALSE(IsENSTLD("test.crypto"));
EXPECT_FALSE(IsENSTLD("eth"));
}

TEST_F(UtilsUnitTest, IsSnsTLD) {
EXPECT_TRUE(IsSnsTLD("test.sol"));
EXPECT_FALSE(IsSnsTLD("test.com"));
EXPECT_FALSE(IsSnsTLD("test.crypto"));
EXPECT_FALSE(IsSnsTLD("eth"));
}

TEST_F(UtilsUnitTest, IsENSResolveMethodAsk) {
Expand All @@ -65,12 +72,12 @@ TEST_F(UtilsUnitTest, IsENSResolveMethodAsk) {
EXPECT_FALSE(IsENSResolveMethodAsk(local_state()));
}

TEST_F(UtilsUnitTest, IsENSResolveMethodEthereum) {
EXPECT_FALSE(IsENSResolveMethodEthereum(local_state()));
TEST_F(UtilsUnitTest, IsENSResolveMethodEnabledd) {
EXPECT_FALSE(IsENSResolveMethodEnabled(local_state()));

local_state()->SetInteger(kENSResolveMethod,
static_cast<int>(ResolveMethodTypes::ENABLED));
EXPECT_TRUE(IsENSResolveMethodEthereum(local_state()));
EXPECT_TRUE(IsENSResolveMethodEnabled(local_state()));
}

TEST_F(UtilsUnitTest, ResolveMethodMigration) {
Expand All @@ -85,8 +92,8 @@ TEST_F(UtilsUnitTest, ResolveMethodMigration) {
static_cast<int>(ResolveMethodTypes::DEPRECATED_DNS_OVER_HTTPS));
EXPECT_FALSE(IsUnstoppableDomainsResolveMethodAsk(local_state()));
EXPECT_FALSE(IsENSResolveMethodAsk(local_state()));
EXPECT_FALSE(IsUnstoppableDomainsResolveMethodEthereum(local_state()));
EXPECT_FALSE(IsENSResolveMethodEthereum(local_state()));
EXPECT_FALSE(IsUnstoppableDomainsResolveMethodEnabled(local_state()));
EXPECT_FALSE(IsENSResolveMethodEnabled(local_state()));

MigrateObsoleteLocalStatePrefs(local_state());
EXPECT_FALSE(local_state()->HasPrefPath(kUnstoppableDomainsResolveMethod));
Expand Down
28 changes: 19 additions & 9 deletions browser/ipfs/content_browser_client_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,26 @@ bool HandleIPFSURLRewrite(GURL* url, content::BrowserContext* browser_context) {
}
}

bool resolve_ens = decentralized_dns::IsENSTLD(*url) &&
decentralized_dns::IsENSResolveMethodEthereum(
g_browser_process->local_state());
bool resolve_ud =
decentralized_dns::IsUnstoppableDomainsTLD(*url) &&
decentralized_dns::IsUnstoppableDomainsResolveMethodEthereum(
g_browser_process->local_state());
if ((resolve_ens || resolve_ud) && IsLocalGatewayConfigured(prefs)) {
return true;
if (IsLocalGatewayConfigured(prefs)) {
if (decentralized_dns::IsENSTLD(url->host_piece()) &&
decentralized_dns::IsENSResolveMethodEnabled(
g_browser_process->local_state())) {
return true;
}

if (decentralized_dns::IsSnsTLD(url->host_piece()) &&
decentralized_dns::IsSnsResolveMethodEnabled(
g_browser_process->local_state())) {
return true;
}

if (decentralized_dns::IsUnstoppableDomainsTLD(url->host_piece()) &&
decentralized_dns::IsUnstoppableDomainsResolveMethodEnabled(
g_browser_process->local_state())) {
return true;
}
}
yrliou marked this conversation as resolved.
Show resolved Hide resolved

return false;
}

Expand Down
33 changes: 30 additions & 3 deletions browser/ipfs/content_browser_client_helper_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -189,17 +189,44 @@ TEST_F(ContentBrowserClientHelperUnitTest, HandleIPFSURLRewriteLocal) {
ASSERT_TRUE(HandleIPFSURLRewrite(&ipfs_uri, browser_context()));
}

TEST_F(ContentBrowserClientHelperUnitTest, HandleIPFSURLRewriteENS) {
TEST_F(ContentBrowserClientHelperUnitTest, HandleIPFSURLRewriteDDns) {
profile()->GetPrefs()->SetInteger(
kIPFSResolveMethod, static_cast<int>(IPFSResolveMethodTypes::IPFS_LOCAL));
EXPECT_FALSE(decentralized_dns::IsENSResolveMethodEthereum(local_state()));

EXPECT_FALSE(decentralized_dns::IsENSResolveMethodEnabled(local_state()));
GURL ens_uri("https://brave.eth");
ASSERT_FALSE(HandleIPFSURLRewrite(&ens_uri, browser_context()));
local_state()->SetInteger(
decentralized_dns::kENSResolveMethod,
static_cast<int>(decentralized_dns::ResolveMethodTypes::ENABLED));
EXPECT_TRUE(decentralized_dns::IsENSResolveMethodEthereum(local_state()));
EXPECT_TRUE(decentralized_dns::IsENSResolveMethodEnabled(local_state()));
ASSERT_TRUE(HandleIPFSURLRewrite(&ens_uri, browser_context()));

EXPECT_FALSE(decentralized_dns::IsSnsResolveMethodEnabled(local_state()));
GURL sns_uri("https://brave.sol");
ASSERT_FALSE(HandleIPFSURLRewrite(&sns_uri, browser_context()));
local_state()->SetInteger(
decentralized_dns::kSnsResolveMethod,
static_cast<int>(decentralized_dns::ResolveMethodTypes::ENABLED));
EXPECT_TRUE(decentralized_dns::IsSnsResolveMethodEnabled(local_state()));
ASSERT_TRUE(HandleIPFSURLRewrite(&sns_uri, browser_context()));

EXPECT_FALSE(decentralized_dns::IsUnstoppableDomainsResolveMethodEnabled(
local_state()));
GURL ud_uri("https://brave.crypto");
ASSERT_FALSE(HandleIPFSURLRewrite(&ud_uri, browser_context()));
local_state()->SetInteger(
decentralized_dns::kUnstoppableDomainsResolveMethod,
static_cast<int>(decentralized_dns::ResolveMethodTypes::ENABLED));
EXPECT_TRUE(decentralized_dns::IsUnstoppableDomainsResolveMethodEnabled(
local_state()));
ASSERT_TRUE(HandleIPFSURLRewrite(&ud_uri, browser_context()));

profile()->GetPrefs()->SetInteger(
kIPFSResolveMethod, static_cast<int>(IPFSResolveMethodTypes::IPFS_ASK));
ASSERT_FALSE(HandleIPFSURLRewrite(&ens_uri, browser_context()));
ASSERT_FALSE(HandleIPFSURLRewrite(&sns_uri, browser_context()));
ASSERT_FALSE(HandleIPFSURLRewrite(&ud_uri, browser_context()));
}

TEST_F(ContentBrowserClientHelperUnitTest, HandleIPNSURLRewriteLocal) {
Expand Down
Loading