From 8c396078a99333e75320af6f35483e283b30e338 Mon Sep 17 00:00:00 2001 From: Anton Paymyshev Date: Mon, 13 Jan 2025 16:16:16 +0700 Subject: [PATCH] Support resolving on Base chain for UD --- ...ed_dns_network_delegate_helper_unittest.cc | 39 +++++++++ .../browser/brave_wallet_utils.cc | 15 ++-- .../brave_wallet/browser/brave_wallet_utils.h | 2 +- .../brave_wallet/browser/json_rpc_service.cc | 11 +-- .../browser/json_rpc_service_unittest.cc | 82 +++++++++++++++++++ .../brave_wallet/browser/network_manager.cc | 2 + .../unstoppable_domains_multichain_calls.cc | 12 ++- ...pable_domains_multichain_calls_unittest.cc | 38 +++++++++ 8 files changed, 188 insertions(+), 13 deletions(-) diff --git a/browser/net/decentralized_dns_network_delegate_helper_unittest.cc b/browser/net/decentralized_dns_network_delegate_helper_unittest.cc index 6325ed324aa7..04320e88db7e 100644 --- a/browser/net/decentralized_dns_network_delegate_helper_unittest.cc +++ b/browser/net/decentralized_dns_network_delegate_helper_unittest.cc @@ -221,6 +221,9 @@ TEST_F(DecentralizedDnsNetworkDelegateHelperTest, auto eth_spec = brave_wallet::NetworkManager::GetUnstoppableDomainsRpcUrl( brave_wallet::mojom::kMainnetChainId) .spec(); + auto base_spec = brave_wallet::NetworkManager::GetUnstoppableDomainsRpcUrl( + brave_wallet::mojom::kBaseMainnetChainId) + .spec(); // No redirect for failed requests. EXPECT_EQ(net::ERR_IO_PENDING, @@ -236,6 +239,11 @@ TEST_F(DecentralizedDnsNetworkDelegateHelperTest, brave_wallet::MakeJsonRpcStringArrayResponse( {"", "", "", "", "", "https://brave.com"}), net::HTTP_REQUEST_TIMEOUT); + test_url_loader_factory().SimulateResponseForPendingRequest( + base_spec, + brave_wallet::MakeJsonRpcStringArrayResponse( + {"", "", "", "", "", "https://brave.com"}), + net::HTTP_REQUEST_TIMEOUT); task_environment_.RunUntilIdle(); EXPECT_TRUE(brave_request_info->new_url_spec.empty()); @@ -248,6 +256,11 @@ TEST_F(DecentralizedDnsNetworkDelegateHelperTest, brave_wallet::MakeJsonRpcStringArrayResponse( {"", "", "", "", "", "https://brave.com"}), net::HTTP_OK); + test_url_loader_factory().SimulateResponseForPendingRequest( + base_spec, + brave_wallet::MakeJsonRpcStringArrayResponse( + {"", "", "", "", "", "https://brave.com/base"}), + net::HTTP_OK); test_url_loader_factory().SimulateResponseForPendingRequest( eth_spec, brave_wallet::MakeJsonRpcStringArrayResponse( @@ -257,6 +270,28 @@ TEST_F(DecentralizedDnsNetworkDelegateHelperTest, task_environment_.RunUntilIdle(); EXPECT_EQ(brave_request_info->new_url_spec, "https://brave.com/"); + // Base result. + EXPECT_EQ(net::ERR_IO_PENDING, + OnBeforeURLRequest_DecentralizedDnsPreRedirectWork( + base::DoNothing(), brave_request_info)); + test_url_loader_factory().SimulateResponseForPendingRequest( + polygon_spec, + brave_wallet::MakeJsonRpcStringArrayResponse({"", "", "", "", "", ""}), + net::HTTP_OK); + test_url_loader_factory().SimulateResponseForPendingRequest( + base_spec, + brave_wallet::MakeJsonRpcStringArrayResponse( + {"", "", "", "", "", "https://brave.com/base"}), + net::HTTP_OK); + test_url_loader_factory().SimulateResponseForPendingRequest( + eth_spec, + brave_wallet::MakeJsonRpcStringArrayResponse( + {"QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", "", "", "", "", + ""}), + net::HTTP_OK); + task_environment_.RunUntilIdle(); + EXPECT_EQ(brave_request_info->new_url_spec, "https://brave.com/base"); + // Eth result. EXPECT_EQ(net::ERR_IO_PENDING, OnBeforeURLRequest_DecentralizedDnsPreRedirectWork( @@ -265,6 +300,10 @@ TEST_F(DecentralizedDnsNetworkDelegateHelperTest, polygon_spec, brave_wallet::MakeJsonRpcStringArrayResponse({"", "", "", "", "", ""}), net::HTTP_OK); + test_url_loader_factory().SimulateResponseForPendingRequest( + base_spec, + brave_wallet::MakeJsonRpcStringArrayResponse({"", "", "", "", "", ""}), + net::HTTP_OK); test_url_loader_factory().SimulateResponseForPendingRequest( eth_spec, brave_wallet::MakeJsonRpcStringArrayResponse( diff --git a/components/brave_wallet/browser/brave_wallet_utils.cc b/components/brave_wallet/browser/brave_wallet_utils.cc index 8665e2615140..bea236ed3465 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.cc +++ b/components/brave_wallet/browser/brave_wallet_utils.cc @@ -67,14 +67,17 @@ bool IsValidEntropySize(size_t entropy_size) { return true; } -// Addresses taken from https://docs.unstoppabledomains.com/developer-toolkit/ -// smart-contracts/uns-smart-contracts/#proxyreader -const base::flat_map +const base::flat_map kUnstoppableDomainsProxyReaderContractAddressMap = { + // https://github.com/unstoppabledomains/uns/blob/abd9e12409094dd6ea8611ebffdade8db49c4b56/uns-config.json#L76 {brave_wallet::mojom::kMainnetChainId, - "0xc3C2BAB5e3e52DBF311b2aAcEf2e40344f19494E"}, + "0x578853aa776Eef10CeE6c4dd2B5862bdcE767A8B"}, + // https://github.com/unstoppabledomains/uns/blob/abd9e12409094dd6ea8611ebffdade8db49c4b56/uns-config.json#L221 {brave_wallet::mojom::kPolygonMainnetChainId, - "0xA3f32c8cd786dc089Bd1fC175F2707223aeE5d00"}}; + "0x91EDd8708062bd4233f4Dd0FCE15A7cb4d500091"}, + // https://github.com/unstoppabledomains/uns/blob/abd9e12409094dd6ea8611ebffdade8db49c4b56/uns-config.json#L545 + {brave_wallet::mojom::kBaseMainnetChainId, + "0x78c4b414e1abdf0de267deda01dffd4cd0817a16"}}; constexpr const char kEnsRegistryContractAddress[] = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"; @@ -550,7 +553,7 @@ std::string GetDefaultBaseCryptocurrency(PrefService* prefs) { return prefs->GetString(kDefaultBaseCryptocurrency); } -std::string GetUnstoppableDomainsProxyReaderContractAddress( +std::string_view GetUnstoppableDomainsProxyReaderContractAddress( std::string_view chain_id) { std::string chain_id_lower = base::ToLowerASCII(chain_id); if (kUnstoppableDomainsProxyReaderContractAddressMap.contains( diff --git a/components/brave_wallet/browser/brave_wallet_utils.h b/components/brave_wallet/browser/brave_wallet_utils.h index 74466f6312d9..2c5f3b552569 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.h +++ b/components/brave_wallet/browser/brave_wallet_utils.h @@ -81,7 +81,7 @@ void SetDefaultBaseCryptocurrency(PrefService* prefs, std::string_view cryptocurrency); std::string GetDefaultBaseCryptocurrency(PrefService* prefs); -std::string GetUnstoppableDomainsProxyReaderContractAddress( +std::string_view GetUnstoppableDomainsProxyReaderContractAddress( std::string_view chain_id); std::string GetEnsRegistryContractAddress(std::string_view chain_id); diff --git a/components/brave_wallet/browser/json_rpc_service.cc b/components/brave_wallet/browser/json_rpc_service.cc index 943a3d1bef48..fa264f358b03 100644 --- a/components/brave_wallet/browser/json_rpc_service.cc +++ b/components/brave_wallet/browser/json_rpc_service.cc @@ -1715,8 +1715,9 @@ void JsonRpcService::UnstoppableDomainsResolveDns( base::BindOnce(&JsonRpcService::OnUnstoppableDomainsResolveDns, weak_ptr_factory_.GetWeakPtr(), domain, chain_id); auto eth_call = eth::eth_call( - "", GetUnstoppableDomainsProxyReaderContractAddress(chain_id), "", "", - "", *data, kEthereumBlockTagLatest); + "", + std::string(GetUnstoppableDomainsProxyReaderContractAddress(chain_id)), + "", "", "", *data, kEthereumBlockTagLatest); RequestInternal(std::move(eth_call), true, NetworkManager::GetUnstoppableDomainsRpcUrl(chain_id), std::move(internal_callback)); @@ -1787,9 +1788,9 @@ void JsonRpcService::UnstoppableDomainsGetWalletAddr( auto internal_callback = base::BindOnce(&JsonRpcService::OnUnstoppableDomainsGetWalletAddr, weak_ptr_factory_.GetWeakPtr(), key, chain_id); - auto eth_call = - eth::eth_call(GetUnstoppableDomainsProxyReaderContractAddress(chain_id), - ToHex(call_data)); + auto eth_call = eth::eth_call( + std::string(GetUnstoppableDomainsProxyReaderContractAddress(chain_id)), + ToHex(call_data)); RequestInternal(std::move(eth_call), true, NetworkManager::GetUnstoppableDomainsRpcUrl(chain_id), std::move(internal_callback)); diff --git a/components/brave_wallet/browser/json_rpc_service_unittest.cc b/components/brave_wallet/browser/json_rpc_service_unittest.cc index aee365701817..16cfe3f4f322 100644 --- a/components/brave_wallet/browser/json_rpc_service_unittest.cc +++ b/components/brave_wallet/browser/json_rpc_service_unittest.cc @@ -3233,6 +3233,14 @@ class UnstoppableDomainsUnitTest : public JsonRpcServiceUnitTest { polygon_endpoint_handler_->AddEthCallHandler( polygon_getmany_call_handler_.get()); + base_endpoint_handler_ = std::make_unique( + NetworkManager::GetUnstoppableDomainsRpcUrl( + mojom::kBaseMainnetChainId)); + base_getmany_call_handler_ = std::make_unique( + EthAddress::FromHex(GetUnstoppableDomainsProxyReaderContractAddress( + mojom::kBaseMainnetChainId))); + base_endpoint_handler_->AddEthCallHandler(base_getmany_call_handler_.get()); + url_loader_factory_.SetInterceptor(base::BindRepeating( &UnstoppableDomainsUnitTest::HandleRequest, base::Unretained(this))); } @@ -3245,6 +3253,10 @@ class UnstoppableDomainsUnitTest : public JsonRpcServiceUnitTest { static constexpr char k0x3a2f3fAddr[] = "0x3a2f3f7aab82d69036763cfd3f755975f84496e6"; + // Base: test.bald -> 0x1111111111111111111111111111111111111111 + static constexpr char k0x111111Addr[] = + "0x1111111111111111111111111111111111111111"; + void SetEthResponse(const std::string& domain, const std::string& response) { eth_mainnet_getmany_call_handler_->Reset(); eth_mainnet_getmany_call_handler_->AddItem(domain, "crypto.ETH.address", @@ -3272,6 +3284,18 @@ class UnstoppableDomainsUnitTest : public JsonRpcServiceUnitTest { polygon_getmany_call_handler_->Reset(); polygon_getmany_call_handler_->SetRawResponse("timeout"); } + void SetBaseResponse(const std::string& domain, const std::string& response) { + base_getmany_call_handler_->Reset(); + base_getmany_call_handler_->AddItem(domain, "crypto.ETH.address", response); + } + void SetBaseRawResponse(const std::string& response) { + base_getmany_call_handler_->Reset(); + base_getmany_call_handler_->SetRawResponse(response); + } + void SetBaseTimeoutResponse() { + base_getmany_call_handler_->Reset(); + base_getmany_call_handler_->SetRawResponse("timeout"); + } std::string DnsIpfsResponse() const { return MakeJsonRpcStringArrayResponse( @@ -3299,9 +3323,11 @@ class UnstoppableDomainsUnitTest : public JsonRpcServiceUnitTest { protected: std::unique_ptr eth_mainnet_endpoint_handler_; std::unique_ptr polygon_endpoint_handler_; + std::unique_ptr base_endpoint_handler_; std::unique_ptr eth_mainnet_getmany_call_handler_; std::unique_ptr polygon_getmany_call_handler_; + std::unique_ptr base_getmany_call_handler_; void HandleRequest(const network::ResourceRequest& request) { url_loader_factory_.ClearResponses(); @@ -3320,6 +3346,13 @@ class UnstoppableDomainsUnitTest : public JsonRpcServiceUnitTest { } else { url_loader_factory_.AddResponse(request.url.spec(), *response); } + } else if ((response = base_endpoint_handler_->HandleRequest(request))) { + if (response == "timeout") { + url_loader_factory_.AddResponse(request.url.spec(), "", + net::HTTP_REQUEST_TIMEOUT); + } else { + url_loader_factory_.AddResponse(request.url.spec(), *response); + } } else { url_loader_factory_.AddResponse(request.url.spec(), "", net::HTTP_INTERNAL_SERVER_ERROR); @@ -3389,6 +3422,25 @@ TEST_F(UnstoppableDomainsUnitTest, GetWalletAddr_PolygonResult) { task_environment_.RunUntilIdle(); } +TEST_F(UnstoppableDomainsUnitTest, GetWalletAddr_BaseResult) { + base::MockCallback callback; + EXPECT_CALL(callback, Run(k0x111111Addr, mojom::ProviderError::kSuccess, "")); + SetEthResponse("javajobs.crypto", ""); + SetPolygonResponse("javajobs.crypto", ""); + SetBaseResponse("javajobs.crypto", k0x111111Addr); + json_rpc_service_->UnstoppableDomainsGetWalletAddr( + "javajobs.crypto", MakeToken(), callback.Get()); + WaitAndVerify(&callback); + + EXPECT_CALL(callback, Run(k0x111111Addr, mojom::ProviderError::kSuccess, "")); + SetEthResponse("javajobs.crypto", k0x8aaD44Addr); + SetPolygonResponse("javajobs.crypto", ""); + SetBaseResponse("javajobs.crypto", k0x111111Addr); + json_rpc_service_->UnstoppableDomainsGetWalletAddr( + "javajobs.crypto", MakeToken(), callback.Get()); + WaitAndVerify(&callback); +} + TEST_F(UnstoppableDomainsUnitTest, GetWalletAddr_FallbackToEthMainnet) { base::MockCallback callback; EXPECT_CALL(callback, Run(k0x8aaD44Addr, mojom::ProviderError::kSuccess, "")); @@ -3571,6 +3623,36 @@ TEST_F(UnstoppableDomainsUnitTest, ResolveDns_PolygonResult) { WaitAndVerify(&callback); } +TEST_F(UnstoppableDomainsUnitTest, ResolveDns_BaseResult) { + base::MockCallback callback; + EXPECT_CALL(callback, Run(std::optional("https://brave.com"), + mojom::ProviderError::kSuccess, "")); + SetEthTimeoutResponse(); + SetPolygonRawResponse(DnsEmptyResponse()); + SetBaseRawResponse(DnsBraveResponse()); + json_rpc_service_->UnstoppableDomainsResolveDns("brave.crypto", + callback.Get()); + WaitAndVerify(&callback); + + EXPECT_CALL(callback, Run(std::optional("https://brave.com"), + mojom::ProviderError::kSuccess, "")); + SetEthRawResponse(DnsIpfsResponse()); + SetPolygonRawResponse(DnsEmptyResponse()); + SetBaseRawResponse(DnsBraveResponse()); + json_rpc_service_->UnstoppableDomainsResolveDns("brave.crypto", + callback.Get()); + WaitAndVerify(&callback); + + EXPECT_CALL(callback, Run(std::optional("https://brave.com"), + mojom::ProviderError::kSuccess, "")); + SetEthRawResponse(DnsEmptyResponse()); + SetPolygonRawResponse(DnsEmptyResponse()); + SetBaseRawResponse(DnsBraveResponse()); + json_rpc_service_->UnstoppableDomainsResolveDns("brave.crypto", + callback.Get()); + WaitAndVerify(&callback); +} + TEST_F(UnstoppableDomainsUnitTest, ResolveDns_FallbackToEthMainnet) { base::MockCallback callback; EXPECT_CALL( diff --git a/components/brave_wallet/browser/network_manager.cc b/components/brave_wallet/browser/network_manager.cc index 0c838904a2df..fd383d08722d 100644 --- a/components/brave_wallet/browser/network_manager.cc +++ b/components/brave_wallet/browser/network_manager.cc @@ -957,6 +957,8 @@ GURL NetworkManager::GetUnstoppableDomainsRpcUrl(std::string_view chain_id) { return GetEthMainnet()->rpc_endpoints.front(); } else if (chain_id == mojom::kPolygonMainnetChainId) { return GetPolygonMainnet()->rpc_endpoints.front(); + } else if (chain_id == mojom::kBaseMainnetChainId) { + return GetBaseMainnet()->rpc_endpoints.front(); } NOTREACHED(); diff --git a/components/brave_wallet/browser/unstoppable_domains_multichain_calls.cc b/components/brave_wallet/browser/unstoppable_domains_multichain_calls.cc index 7be70100d58f..b8b1be5cc581 100644 --- a/components/brave_wallet/browser/unstoppable_domains_multichain_calls.cc +++ b/components/brave_wallet/browser/unstoppable_domains_multichain_calls.cc @@ -54,6 +54,11 @@ MultichainCall::GetEffectiveResponse() { return nullptr; } + auto base_result = responses_.find(mojom::kBaseMainnetChainId); + if (base_result == responses_.end()) { + return nullptr; + } + auto eth_mainnet_result = responses_.find(mojom::kMainnetChainId); if (eth_mainnet_result == responses_.end()) { return nullptr; @@ -63,6 +68,10 @@ MultichainCall::GetEffectiveResponse() { return &polygon_result->second; } + if (base_result->second.result || base_result->second.error) { + return &base_result->second; + } + return ð_mainnet_result->second; } @@ -86,7 +95,8 @@ bool MultichainCall::MaybeResolveCallbacks() { template std::vector MultichainCalls::GetChains() const { - return {mojom::kPolygonMainnetChainId, mojom::kMainnetChainId}; + return {mojom::kPolygonMainnetChainId, mojom::kBaseMainnetChainId, + mojom::kMainnetChainId}; } template diff --git a/components/brave_wallet/browser/unstoppable_domains_multichain_calls_unittest.cc b/components/brave_wallet/browser/unstoppable_domains_multichain_calls_unittest.cc index eb8a861276d5..3bf6ab4e2b32 100644 --- a/components/brave_wallet/browser/unstoppable_domains_multichain_calls_unittest.cc +++ b/components/brave_wallet/browser/unstoppable_domains_multichain_calls_unittest.cc @@ -43,6 +43,7 @@ TEST_F(MultichainCallsUnitTest, ManyCallbacks) { chain_calls().AddCallback(domain(), cb2.Get()); chain_calls().SetResult(domain(), mojom::kPolygonMainnetChainId, "polygon"); + chain_calls().SetResult(domain(), mojom::kBaseMainnetChainId, "base"); base::RunLoop().RunUntilIdle(); testing::Mock::VerifyAndClearExpectations(&cb1); testing::Mock::VerifyAndClearExpectations(&cb2); @@ -50,6 +51,7 @@ TEST_F(MultichainCallsUnitTest, ManyCallbacks) { EXPECT_CALL(cb1, Run("polygon", mojom::ProviderError::kSuccess, "")); EXPECT_CALL(cb2, Run("polygon", mojom::ProviderError::kSuccess, "")); chain_calls().SetResult(domain(), mojom::kMainnetChainId, "mainnet"); + chain_calls().SetResult(domain(), mojom::kBaseMainnetChainId, "base"); EXPECT_FALSE(chain_calls().HasCall(domain())); base::RunLoop().RunUntilIdle(); @@ -64,6 +66,38 @@ TEST_F(MultichainCallsUnitTest, PolygonResult) { chain_calls().AddCallback(domain(), cb1.Get()); chain_calls().SetResult(domain(), mojom::kPolygonMainnetChainId, "polygon"); + chain_calls().SetResult(domain(), mojom::kBaseMainnetChainId, "base"); + chain_calls().SetResult(domain(), mojom::kMainnetChainId, "mainnet"); + + base::RunLoop().RunUntilIdle(); +} + +TEST_F(MultichainCallsUnitTest, BaseError) { + EXPECT_FALSE(chain_calls().HasCall(domain())); + + base::MockCallback cb1; + EXPECT_CALL(cb1, Run("", mojom::ProviderError::kInternalError, "some error")); + + chain_calls().AddCallback(domain(), cb1.Get()); + + chain_calls().SetError(domain(), mojom::kBaseMainnetChainId, + mojom::ProviderError::kInternalError, "some error"); + chain_calls().SetNoResult(domain(), mojom::kPolygonMainnetChainId); + chain_calls().SetResult(domain(), mojom::kMainnetChainId, "mainnet"); + + base::RunLoop().RunUntilIdle(); +} + +TEST_F(MultichainCallsUnitTest, BaseResult) { + EXPECT_FALSE(chain_calls().HasCall(domain())); + + base::MockCallback cb1; + EXPECT_CALL(cb1, Run("base", mojom::ProviderError::kSuccess, "")); + + chain_calls().AddCallback(domain(), cb1.Get()); + + chain_calls().SetNoResult(domain(), mojom::kPolygonMainnetChainId); + chain_calls().SetResult(domain(), mojom::kBaseMainnetChainId, "base"); chain_calls().SetResult(domain(), mojom::kMainnetChainId, "mainnet"); base::RunLoop().RunUntilIdle(); @@ -79,6 +113,7 @@ TEST_F(MultichainCallsUnitTest, PolygonError) { chain_calls().SetError(domain(), mojom::kPolygonMainnetChainId, mojom::ProviderError::kInternalError, "some error"); + chain_calls().SetResult(domain(), mojom::kBaseMainnetChainId, "base"); chain_calls().SetResult(domain(), mojom::kMainnetChainId, "mainnet"); base::RunLoop().RunUntilIdle(); @@ -93,6 +128,7 @@ TEST_F(MultichainCallsUnitTest, MainnetResult) { chain_calls().AddCallback(domain(), cb1.Get()); chain_calls().SetNoResult(domain(), mojom::kPolygonMainnetChainId); + chain_calls().SetNoResult(domain(), mojom::kBaseMainnetChainId); chain_calls().SetResult(domain(), mojom::kMainnetChainId, "mainnet"); base::RunLoop().RunUntilIdle(); @@ -107,6 +143,7 @@ TEST_F(MultichainCallsUnitTest, MainnetError) { chain_calls().AddCallback(domain(), cb1.Get()); chain_calls().SetNoResult(domain(), mojom::kPolygonMainnetChainId); + chain_calls().SetNoResult(domain(), mojom::kBaseMainnetChainId); chain_calls().SetError(domain(), mojom::kMainnetChainId, mojom::ProviderError::kInternalError, "some error"); @@ -122,6 +159,7 @@ TEST_F(MultichainCallsUnitTest, NoResult) { chain_calls().AddCallback(domain(), cb1.Get()); chain_calls().SetNoResult(domain(), mojom::kPolygonMainnetChainId); + chain_calls().SetNoResult(domain(), mojom::kBaseMainnetChainId); chain_calls().SetNoResult(domain(), mojom::kMainnetChainId); base::RunLoop().RunUntilIdle();