diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java b/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java index a5148312c2a..bb36037951a 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java @@ -362,49 +362,6 @@ public class AsyncUtils { } } - public abstract static class BaseGetNftMetadataContext extends SingleResponseBaseContext { - public BlockchainToken asset; - public String tokenMetadata; - public Integer errorCode; - public String errorMessage; - - public BaseGetNftMetadataContext(Runnable responseCompleteCallback) { - super(responseCompleteCallback); - } - } - - public static class GetNftSolanaMetadataContext extends BaseGetNftMetadataContext - implements JsonRpcService.GetSolTokenMetadata_Response { - public GetNftSolanaMetadataContext(Runnable responseCompleteCallback) { - super(responseCompleteCallback); - } - - @Override - public void call( - String tokenUrl, String tokenMetadata, int errorCode, String errorMessage) { - this.tokenMetadata = tokenMetadata; - this.errorCode = errorCode; - this.errorMessage = errorMessage; - super.fireResponseCompleteCallback(); - } - } - - public static class GetNftErc721MetadataContext extends BaseGetNftMetadataContext - implements JsonRpcService.GetErc721Metadata_Response { - public GetNftErc721MetadataContext(Runnable responseCompleteCallback) { - super(responseCompleteCallback); - } - - @Override - public void call( - String tokenUrl, String erc721Metadata, int errorCode, String errorMessage) { - this.tokenMetadata = erc721Metadata; - this.errorCode = errorCode; - this.errorMessage = errorMessage; - super.fireResponseCompleteCallback(); - } - } - public static class GetNetworkAllTokensContext extends SingleResponseBaseContext implements BlockchainRegistry.GetAllTokens_Response { public BlockchainToken[] tokens; diff --git a/components/brave_wallet/browser/BUILD.gn b/components/brave_wallet/browser/BUILD.gn index 132fa6969ee..7754ab217d1 100644 --- a/components/brave_wallet/browser/BUILD.gn +++ b/components/brave_wallet/browser/BUILD.gn @@ -175,8 +175,6 @@ static_library("browser") { "meld_integration_response_parser.h", "meld_integration_service.cc", "meld_integration_service.h", - "nft_metadata_fetcher.cc", - "nft_metadata_fetcher.h", "nonce_tracker.cc", "nonce_tracker.h", "password_encryptor.cc", @@ -768,7 +766,6 @@ source_set("unit_tests") { "meld_integration_response_parser_unittest.cc", "meld_integration_service_unittest.cc", "network_manager_unittest.cc", - "nft_metadata_fetcher_unittest.cc", "password_encryptor_unittest.cc", "polkadot/polkadot_block_header_unittest.cc", "polkadot/polkadot_block_tracker_unittest.cc", diff --git a/components/brave_wallet/browser/brave_wallet_constants.h b/components/brave_wallet/browser/brave_wallet_constants.h index a56e26d0263..f974514d0fc 100644 --- a/components/brave_wallet/browser/brave_wallet_constants.h +++ b/components/brave_wallet/browser/brave_wallet_constants.h @@ -1822,9 +1822,7 @@ inline constexpr char kCryptoFilAddressKey[] = "crypto.FIL.address"; // ERC-165 identifier for ERC721 interface. inline constexpr char kERC1155InterfaceId[] = "0xd9b67a26"; -inline constexpr char kERC1155MetadataInterfaceId[] = "0x0e89341c"; inline constexpr char kERC721InterfaceId[] = "0x80ac58cd"; -inline constexpr char kERC721MetadataInterfaceId[] = "0x5b5e139f"; inline constexpr char kEthereumBlockTagEarliest[] = "earliest"; inline constexpr char kEthereumBlockTagLatest[] = "latest"; diff --git a/components/brave_wallet/browser/eth_data_builder.cc b/components/brave_wallet/browser/eth_data_builder.cc index 38d77a129b6..175bb55f5a2 100644 --- a/components/brave_wallet/browser/eth_data_builder.cc +++ b/components/brave_wallet/browser/eth_data_builder.cc @@ -191,17 +191,6 @@ bool OwnerOf(uint256_t token_id, std::string* data) { return brave_wallet::ConcatHexStrings(function_hash, padded_token_id, data); } -bool TokenUri(uint256_t token_id, std::string* data) { - const std::string function_hash = GetFunctionHash("tokenURI(uint256)"); - - std::string padded_token_id; - if (!PadHexEncodedParameter(Uint256ValueToHex(token_id), &padded_token_id)) { - return false; - } - - return brave_wallet::ConcatHexStrings(function_hash, padded_token_id, data); -} - } // namespace erc721 namespace erc1155 { @@ -278,16 +267,6 @@ bool BalanceOf(std::string_view owner_address, return ConcatHexStrings(hex_strings, data); } -bool Uri(uint256_t token_id, std::string* data) { - const std::string function_hash = GetFunctionHash("uri(uint256)"); - std::string padded_token_id; - if (!PadHexEncodedParameter(Uint256ValueToHex(token_id), &padded_token_id)) { - return false; - } - - return brave_wallet::ConcatHexStrings(function_hash, padded_token_id, data); -} - } // namespace erc1155 namespace erc165 { diff --git a/components/brave_wallet/browser/eth_data_builder.h b/components/brave_wallet/browser/eth_data_builder.h index a325c48d7fe..be1f4c8fec4 100644 --- a/components/brave_wallet/browser/eth_data_builder.h +++ b/components/brave_wallet/browser/eth_data_builder.h @@ -57,9 +57,6 @@ bool TransferFromOrSafeTransferFrom(bool is_safe_transfer_from, // Find the owner of an NFT. bool OwnerOf(uint256_t token_id, std::string* data); -// Get the URI of an NFT. -bool TokenUri(uint256_t token_id, std::string* data); - } // namespace erc721 namespace erc1155 { @@ -76,9 +73,6 @@ bool BalanceOf(std::string_view owner_address, uint256_t token_id, std::string* data); -// Get the URI of a token -bool Uri(uint256_t token_id, std::string* data); - } // namespace erc1155 namespace erc165 { diff --git a/components/brave_wallet/browser/eth_data_builder_unittest.cc b/components/brave_wallet/browser/eth_data_builder_unittest.cc index 4ad84d7370f..cc664059e71 100644 --- a/components/brave_wallet/browser/eth_data_builder_unittest.cc +++ b/components/brave_wallet/browser/eth_data_builder_unittest.cc @@ -108,16 +108,6 @@ TEST(EthCallDataBuilderTest, OwnerOf) { "0000000f"); } -TEST(EthCallDataBuilderTest, TokenUri) { - std::string data; - uint256_t token_id; - ASSERT_TRUE(HexValueToUint256("0xf", &token_id)); - TokenUri(token_id, &data); - ASSERT_EQ(data, - "0xc87b56dd00000000000000000000000000000000000000000000000000000000" - "0000000f"); -} - } // namespace erc721 namespace erc1155 { @@ -153,16 +143,6 @@ TEST(EthCallDataBuilderTest, BalanceOf_erc1155) { "b60000000000000000000000000000000000000000000000000000000000000001"); } -TEST(EthCallDataBuilderTest, Uri) { - std::string data; - uint256_t token_id; - ASSERT_TRUE(HexValueToUint256("0xf", &token_id)); - Uri(token_id, &data); - ASSERT_EQ(data, - "0x0e89341c00000000000000000000000000000000000000000000000000000000" - "0000000f"); -} - } // namespace erc1155 namespace erc165 { diff --git a/components/brave_wallet/browser/eth_response_parser.cc b/components/brave_wallet/browser/eth_response_parser.cc index acdf154660c..8593e835cea 100644 --- a/components/brave_wallet/browser/eth_response_parser.cc +++ b/components/brave_wallet/browser/eth_response_parser.cc @@ -364,33 +364,4 @@ std::optional ParseUnstoppableDomainsProxyReaderGet( return value; } -bool ParseTokenUri(const base::Value& json_value, GURL* url) { - std::string result; - if (!ParseStringResult(json_value, &result)) { - return false; - } - - GURL result_url = GURL(result); - if (!result_url.is_valid()) { - return false; - } - - *url = result_url; - return true; -} - -bool ParseDataURIAndExtractJSON(const GURL url, std::string* json) { - std::string mime_type, charset, data; - if (!net::DataURL::Parse(url, &mime_type, &charset, &data) || data.empty()) { - return false; - } - - if (mime_type != "application/json") { - return false; - } - - *json = data; - return true; -} - } // namespace brave_wallet::eth diff --git a/components/brave_wallet/browser/eth_response_parser.h b/components/brave_wallet/browser/eth_response_parser.h index eba9260eebc..e4d3df3436b 100644 --- a/components/brave_wallet/browser/eth_response_parser.h +++ b/components/brave_wallet/browser/eth_response_parser.h @@ -59,11 +59,6 @@ ParseUnstoppableDomainsProxyReaderGetMany(const base::Value& json_value); std::optional ParseUnstoppableDomainsProxyReaderGet( const base::Value& json_value); -// Get the JSON included in a data URI with a mime type application/json -bool ParseDataURIAndExtractJSON(const GURL url, std::string* json); - -bool ParseTokenUri(const base::Value& json_value, GURL* url); - } // namespace eth } // namespace brave_wallet diff --git a/components/brave_wallet/browser/eth_response_parser_unittest.cc b/components/brave_wallet/browser/eth_response_parser_unittest.cc index 9746a9f83c2..cd46637b3c0 100644 --- a/components/brave_wallet/browser/eth_response_parser_unittest.cc +++ b/components/brave_wallet/browser/eth_response_parser_unittest.cc @@ -609,91 +609,6 @@ TEST(EthResponseParserUnitTest, ParseEthGetFeeHistory) { &gas_used_ratio, &oldest_block, &reward)); } -TEST(EthResponseParserUnitTest, ParseDataURIAndExtractJSON) { - std::string json; - std::string url; - // Invalid URL - EXPECT_FALSE(ParseDataURIAndExtractJSON(GURL(""), &json)); - // Valid URL, incorrect scheme - EXPECT_FALSE(ParseDataURIAndExtractJSON(GURL("https://brave.com"), - &json)); // Incorrect scheme - // Valid URL and scheme, invalid mime_type - EXPECT_FALSE(ParseDataURIAndExtractJSON( - GURL("data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh"), - &json)); // Incorrect mime type - - // All valid - std::string expected = - R"({"attributes":"","description":"Non fungible lion","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MDAgNTAwIj48cGF0aCBkPSIiLz48L3N2Zz4=","name":"NFL"})"; - url = - "data:application/" - "json;base64," - "eyJhdHRyaWJ1dGVzIjoiIiwiZGVzY3JpcHRpb24iOiJOb24gZnVuZ2libGUgbGlvbiIsImlt" - "YWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNE" - "b3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhacFpYZENiM2c5SWpBZ01DQTFNREFn" - "TlRBd0lqNDhjR0YwYUNCa1BTSWlMejQ4TDNOMlp6ND0iLCJuYW1lIjoiTkZMIn0="; - EXPECT_TRUE(ParseDataURIAndExtractJSON(GURL(url), &json)); - EXPECT_EQ(json, expected); -} - -TEST(EthResponseParserUnitTest, ParseTokenUri) { - GURL url; - - // Valid (3 total) - // (1/3) Valid IPFS URLs - std::string body = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003a697066733a2f2f516d65536a53696e4870506e6d586d73704d6a776958794e367a533445397a63636172694752336a7863615774712f31383137000000000000" - })"; - EXPECT_TRUE(eth::ParseTokenUri(ParseJson(body), &url)); - EXPECT_EQ(url.spec(), - "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/1817"); - - // (2/3) Data URIs are parsed - body = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000135646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c65794a686448527961574a316447567a496a6f69496977695a47567a59334a7063485270623234694f694a4f623234675a6e56755a326c696247556762476c7662694973496d6c745957646c496a6f695a474630595470706257466e5a53397a646d6372654731734f324a68633255324e43785153453479576e6c434e474a586548566a656a4270595568534d474e4562335a4d4d32517a5a486b314d3031354e585a6a62574e3254577042643031444f58706b62574e7053556861634670595a454e694d326335535770425a3031445154464e5245466e546c524264306c714e44686a5230597759554e436131425453576c4d656a513454444e4f4d6c70364e4430694c434a755957316c496a6f69546b5a4d496e303d0000000000000000000000" - })"; - EXPECT_TRUE(eth::ParseTokenUri(ParseJson(body), &url)); - EXPECT_EQ( - url.spec(), - R"(data:application/json;base64,eyJhdHRyaWJ1dGVzIjoiIiwiZGVzY3JpcHRpb24iOiJOb24gZnVuZ2libGUgbGlvbiIsImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhacFpYZENiM2c5SWpBZ01DQTFNREFnTlRBd0lqNDhjR0YwYUNCa1BTSWlMejQ4TDNOMlp6ND0iLCJuYW1lIjoiTkZMIn0=)"); - - // (3/3) HTTP URLs are parsed - body = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002468747470733a2f2f696e76697369626c65667269656e64732e696f2f6170692f3138313700000000000000000000000000000000000000000000000000000000" - })"; - EXPECT_TRUE(eth::ParseTokenUri(ParseJson(body), &url)); - EXPECT_EQ(url.spec(), "https://invisiblefriends.io/api/1817"); - - // Invalid (2 total) - // (1/2) Invalid provider response returns false - url = GURL(); - body = R"({ - "jsonrpc":"2.0", - "id":1, - "error": { - "code":-32005, - "message": "Request exceeds defined limit" - } - })"; - EXPECT_FALSE(eth::ParseTokenUri(ParseJson(body), &url)); - EXPECT_EQ(url.spec(), ""); - - // (2/2) Invalid URL returns false (https//brave.com) - body = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001068747470732f2f62726176652e636f6d00000000000000000000000000000000" - })"; - EXPECT_FALSE(eth::ParseTokenUri(ParseJson(body), &url)); - EXPECT_EQ(url.spec(), ""); -} - TEST(EthResponseParserUnitTest, ParseStringResult) { std::string value; diff --git a/components/brave_wallet/browser/json_rpc_service.cc b/components/brave_wallet/browser/json_rpc_service.cc index 87e074aed74..fa37de35104 100644 --- a/components/brave_wallet/browser/json_rpc_service.cc +++ b/components/brave_wallet/browser/json_rpc_service.cc @@ -38,7 +38,6 @@ #include "brave/components/brave_wallet/browser/json_rpc_requests_helper.h" #include "brave/components/brave_wallet/browser/json_rpc_response_parser.h" #include "brave/components/brave_wallet/browser/network_manager.h" -#include "brave/components/brave_wallet/browser/nft_metadata_fetcher.h" #include "brave/components/brave_wallet/browser/pref_names.h" #include "brave/components/brave_wallet/browser/solana_keyring.h" #include "brave/components/brave_wallet/browser/solana_requests.h" @@ -367,8 +366,6 @@ JsonRpcService::JsonRpcService( api_request_helper_ens_offchain_ = std::make_unique( GetENSOffchainNetworkTrafficAnnotationTag(), url_loader_factory); - nft_metadata_fetcher_ = - std::make_unique(url_loader_factory, this, prefs_); simple_hash_client_ = std::make_unique(url_loader_factory); } @@ -2214,106 +2211,6 @@ void JsonRpcService::ContinueGetERC721TokenBalance( mojom::ProviderError::kSuccess, ""); } -void JsonRpcService::GetERC721Metadata(const std::string& contract_address, - const std::string& token_id, - const std::string& chain_id, - GetERC721MetadataCallback callback) { - nft_metadata_fetcher_->GetEthTokenMetadata( - contract_address, token_id, chain_id, kERC721MetadataInterfaceId, - std::move(callback)); -} - -void JsonRpcService::GetERC1155Metadata(const std::string& contract_address, - const std::string& token_id, - const std::string& chain_id, - GetERC1155MetadataCallback callback) { - nft_metadata_fetcher_->GetEthTokenMetadata( - contract_address, token_id, chain_id, kERC1155MetadataInterfaceId, - std::move(callback)); -} - -void JsonRpcService::GetEthTokenUri(const std::string& chain_id, - const std::string& contract_address, - const std::string& token_id, - const std::string& interface_id, - GetEthTokenUriCallback callback) { - auto network_url = GetNetworkURL(chain_id, mojom::CoinType::ETH); - if (!network_url.is_valid()) { - std::move(callback).Run( - GURL(), mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - return; - } - - if (!EthAddress::IsValidAddress(contract_address)) { - std::move(callback).Run( - GURL(), mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - return; - } - - uint256_t token_id_uint = 0; - if (!HexValueToUint256(token_id, &token_id_uint)) { - std::move(callback).Run( - GURL(), mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - return; - } - - std::string function_signature; - if (interface_id == kERC721MetadataInterfaceId) { - if (!erc721::TokenUri(token_id_uint, &function_signature)) { - std::move(callback).Run( - GURL(), mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - return; - } - } else if (interface_id == kERC1155MetadataInterfaceId) { - if (!erc1155::Uri(token_id_uint, &function_signature)) { - std::move(callback).Run( - GURL(), mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - return; - } - } else { - // Unknown inteface ID - std::move(callback).Run( - GURL(), mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - return; - } - - auto internal_callback = - base::BindOnce(&JsonRpcService::OnGetEthTokenUri, - weak_ptr_factory_.GetWeakPtr(), std::move(callback)); - - RequestInternal(eth::GetCallPayload(contract_address, function_signature), - true, network_url, std::move(internal_callback)); -} - -void JsonRpcService::OnGetEthTokenUri(GetEthTokenUriCallback callback, - APIRequestResult api_request_result) { - if (!api_request_result.Is2XXResponseCode()) { - std::move(callback).Run( - GURL(), mojom::ProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - return; - } - - // Parse response JSON that wraps the result - GURL url; - if (!eth::ParseTokenUri(api_request_result.value_body(), &url)) { - mojom::ProviderError error; - std::string error_message; - ParseErrorResult(api_request_result.value_body(), - &error, &error_message); - std::move(callback).Run(GURL(), error, error_message); - return; - } - - std::move(callback).Run(url, mojom::ProviderError::kSuccess, ""); -} - void JsonRpcService::GetERC1155TokenBalance( const std::string& contract_address, const std::string& token_id, @@ -2962,13 +2859,6 @@ void JsonRpcService::OnGetSPLTokenAccountBalance( mojom::SolanaProviderError::kSuccess, ""); } -void JsonRpcService::GetSolTokenMetadata(const std::string& chain_id, - const std::string& token_mint_address, - GetSolTokenMetadataCallback callback) { - nft_metadata_fetcher_->GetSolTokenMetadata(chain_id, token_mint_address, - std::move(callback)); -} - void JsonRpcService::GetNftMetadatas( std::vector nft_identifiers, GetNftMetadatasCallback callback) { diff --git a/components/brave_wallet/browser/json_rpc_service.h b/components/brave_wallet/browser/json_rpc_service.h index db3ac07a185..b7481fe2183 100644 --- a/components/brave_wallet/browser/json_rpc_service.h +++ b/components/brave_wallet/browser/json_rpc_service.h @@ -44,7 +44,6 @@ class PrefService; namespace brave_wallet { class EnsResolverTask; -class NftMetadataFetcher; class NetworkManager; struct PendingAddChainRequest; struct PendingSwitchChainRequest; @@ -351,28 +350,6 @@ class JsonRpcService : public mojom::JsonRpcService { const std::string& chain_id, GetERC721TokenBalanceCallback callback) override; - using GetEthTokenUriCallback = - base::OnceCallback; - - void GetERC721Metadata(const std::string& contract_address, - const std::string& token_id, - const std::string& chain_id, - GetERC721MetadataCallback callback) override; - - void GetERC1155Metadata(const std::string& contract_address, - const std::string& token_id, - const std::string& chain_id, - GetERC1155MetadataCallback callback) override; - // GetEthTokenUri should only be called after check whether the contract - // supports the ERC721 or ERC1155 interface - void GetEthTokenUri(const std::string& chain_id, - const std::string& contract_address, - const std::string& token_id, - const std::string& interface_id, - GetEthTokenUriCallback callback); - void EthGetLogs(const std::string& chain_id, base::DictValue filter_options, EthGetLogsCallback callback); @@ -463,10 +440,6 @@ class JsonRpcService : public mojom::JsonRpcService { const std::string& token_mint_address, const std::string& chain_id, GetSPLTokenAccountBalanceCallback callback) override; - void GetSolTokenMetadata(const std::string& chain_id, - const std::string& token_mint_address, - GetSolTokenMetadataCallback callback) override; - void IsSolanaBlockhashValid(const std::string& chain_id, const std::string& blockhash, const std::optional& commitment, @@ -711,9 +684,6 @@ class JsonRpcService : public mojom::JsonRpcService { mojom::ProviderError error, const std::string& error_message); - void OnGetEthTokenUri(GetEthTokenUriCallback callback, - const APIRequestResult api_request_result); - void OnGetSupportsInterface(GetSupportsInterfaceCallback callback, APIRequestResult api_request_result); @@ -841,7 +811,6 @@ class JsonRpcService : public mojom::JsonRpcService { raw_ptr network_manager_ = nullptr; const raw_ptr prefs_ = nullptr; const raw_ptr local_state_prefs_ = nullptr; - std::unique_ptr nft_metadata_fetcher_; std::unique_ptr simple_hash_client_; base::WeakPtrFactory weak_ptr_factory_{this}; }; diff --git a/components/brave_wallet/browser/json_rpc_service_unittest.cc b/components/brave_wallet/browser/json_rpc_service_unittest.cc index fe2410b6565..e8f530538ff 100644 --- a/components/brave_wallet/browser/json_rpc_service_unittest.cc +++ b/components/brave_wallet/browser/json_rpc_service_unittest.cc @@ -285,9 +285,6 @@ class TestJsonRpcServiceObserver observer_receiver_{this}; }; -constexpr char https_metadata_response[] = - R"({"attributes":[{"trait_type":"Feet","value":"Green Shoes"},{"trait_type":"Legs","value":"Tan Pants"},{"trait_type":"Suspenders","value":"White Suspenders"},{"trait_type":"Upper Body","value":"Indigo Turtleneck"},{"trait_type":"Sleeves","value":"Long Sleeves"},{"trait_type":"Hat","value":"Yellow / Blue Pointy Beanie"},{"trait_type":"Eyes","value":"White Nerd Glasses"},{"trait_type":"Mouth","value":"Toothpick"},{"trait_type":"Ears","value":"Bing Bong Stick"},{"trait_type":"Right Arm","value":"Swinging"},{"trait_type":"Left Arm","value":"Diamond Hand"},{"trait_type":"Background","value":"Blue"}],"description":"5,000 animated Invisible Friends hiding in the metaverse. A collection by Markus Magnusson & Random Character Collective.","image":"https://rcc.mypinata.cloud/ipfs/QmXmuSenZRnofhGMz2NyT3Yc4Zrty1TypuiBKDcaBsNw9V/1817.gif","name":"Invisible Friends #1817"})"; - std::optional ToValue( const network::ResourceRequest& request) { std::string_view request_string(request.request_body->elements() @@ -959,59 +956,6 @@ class JsonRpcServiceUnitTest : public testing::Test { })); } - void SetTokenMetadataInterceptor( - const std::string& interface_id, - const std::string& chain_id, - const std::string& supports_interface_provider_response, - const std::string& token_uri_provider_response = "", - const std::string& metadata_response = "", - net::HttpStatusCode supports_interface_status = net::HTTP_OK, - net::HttpStatusCode token_uri_status = net::HTTP_OK, - net::HttpStatusCode metadata_status = net::HTTP_OK) { - GURL network_url = - network_manager_->GetNetworkURL(chain_id, mojom::CoinType::ETH); - ASSERT_TRUE(network_url.is_valid()); - url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( - [=, this](const network::ResourceRequest& request) { - url_loader_factory_.ClearResponses(); - if (request.method == - "POST") { // An eth_call, either to supportsInterface or tokenURI - std::string_view request_string(request.request_body->elements() - ->at(0) - .As() - .AsStringPiece()); - bool is_supports_interface_req = - request_string.find(GetFunctionHash( - "supportsInterface(bytes4)")) != std::string::npos; - if (is_supports_interface_req) { - ASSERT_NE(request_string.find(interface_id.substr(2)), - std::string::npos); - EXPECT_EQ(request.url.spec(), network_url); - url_loader_factory_.AddResponse( - network_url.spec(), supports_interface_provider_response, - supports_interface_status); - return; - } else { - std::string function_hash; - if (interface_id == kERC721MetadataInterfaceId) { - function_hash = GetFunctionHash("tokenURI(uint256)"); - } else { - function_hash = GetFunctionHash("uri(uint256)"); - } - ASSERT_NE(request_string.find(function_hash), std::string::npos); - url_loader_factory_.AddResponse(network_url.spec(), - token_uri_provider_response, - token_uri_status); - return; - } - } else { // A HTTP GET to fetch the metadata json from the web - url_loader_factory_.AddResponse(request.url.spec(), - metadata_response, metadata_status); - return; - } - })); - } - void SetGetEthNftStandardInterceptor( const GURL& expected_url, const std::map& interface_id_to_response) { @@ -1039,24 +983,6 @@ class JsonRpcServiceUnitTest : public testing::Test { })); } - void SetSolTokenMetadataInterceptor( - const GURL& expected_rpc_url, - const std::string& get_account_info_response, - const GURL& expected_metadata_url, - const std::string& metadata_response) { - auto network_url = - GetNetwork(mojom::kLocalhostChainId, mojom::CoinType::SOL); - ASSERT_TRUE(expected_rpc_url.is_valid()); - ASSERT_TRUE(expected_metadata_url.is_valid()); - url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( - [=, this](const network::ResourceRequest& request) { - url_loader_factory_.AddResponse(expected_rpc_url.spec(), - get_account_info_response); - url_loader_factory_.AddResponse(expected_metadata_url.spec(), - metadata_response); - })); - } - void SetInterceptor(const GURL& expected_url, const std::string& expected_method, const std::string& expected_cache_header, @@ -1288,66 +1214,6 @@ class JsonRpcServiceUnitTest : public testing::Test { run_loop.Run(); } - void TestGetERC721Metadata(const std::string& contract, - const std::string& token_id, - const std::string& chain_id, - const std::string& expected_response, - mojom::ProviderError expected_error, - const std::string& expected_error_message) { - base::RunLoop run_loop; - json_rpc_service_->GetERC721Metadata( - contract, token_id, chain_id, - base::BindLambdaForTesting( - [&](const std::string& token_url, const std::string& response, - mojom::ProviderError error, const std::string& error_message) { - EXPECT_EQ(response, expected_response); - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - run_loop.Quit(); - })); - run_loop.Run(); - } - - void TestGetERC1155Metadata(const std::string& contract, - const std::string& token_id, - const std::string& chain_id, - const std::string& expected_response, - mojom::ProviderError expected_error, - const std::string& expected_error_message) { - base::RunLoop run_loop; - json_rpc_service_->GetERC1155Metadata( - contract, token_id, chain_id, - base::BindLambdaForTesting( - [&](const std::string& token_url, const std::string& response, - mojom::ProviderError error, const std::string& error_message) { - EXPECT_EQ(response, expected_response); - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - run_loop.Quit(); - })); - run_loop.Run(); - } - - void TestGetEthTokenUri(const std::string& contract, - const std::string& token_id, - const std::string& chain_id, - const std::string& interface_id, - const GURL& expected_uri, - mojom::ProviderError expected_error, - const std::string& expected_error_message) { - base::RunLoop run_loop; - json_rpc_service_->GetEthTokenUri( - chain_id, contract, token_id, interface_id, - base::BindLambdaForTesting([&](const GURL& uri, - mojom::ProviderError error, - const std::string& error_message) { - EXPECT_EQ(uri, expected_uri); - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - run_loop.Quit(); - })); - run_loop.Run(); - } void TestEthGetLogs(const std::string& chain_id, const std::string& from_block, @@ -1862,30 +1728,6 @@ class JsonRpcServiceUnitTest : public testing::Test { json_rpc_service_->AddEthereumChainForOrigin(std::move(chain), origin)); } - void TestGetSolTokenMetadata(const std::string& token_mint_address, - const std::string& expected_response, - mojom::SolanaProviderError expected_error, - const std::string& expected_error_message) { - base::RunLoop loop; - json_rpc_service_->GetSolTokenMetadata( - mojom::kSolanaMainnet, token_mint_address, - base::BindLambdaForTesting([&](const std::string& token_url, - const std::string& response, - mojom::SolanaProviderError error, - const std::string& error_message) { - if (response.empty()) { - EXPECT_EQ(response, expected_response); - } else { - EXPECT_EQ(base::test::ParseJson(response), - base::test::ParseJson(expected_response)); - } - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - loop.Quit(); - })); - loop.Run(); - } - void TestGetNftMetadatas( std::vector nft_identifiers, std::vector expected_metadatas, @@ -4254,48 +4096,6 @@ TEST_F(JsonRpcServiceUnitTest, GetERC721OwnerOf) { EXPECT_TRUE(callback_called); } -TEST_F(JsonRpcServiceUnitTest, GetERC721Metadata) { - // Ensure GetERC721Metadata passes the correct interface ID to - // GetEthTokenMetadata - SetTokenMetadataInterceptor(kERC721MetadataInterfaceId, - mojom::kMainnetChainId, - R"({ - "jsonrpc":"2.0", - "id":1, - "result": "0x0000000000000000000000000000000000000000000000000000000000000001" - })", - R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002468747470733a2f2f696e76697369626c65667269656e64732e696f2f6170692f3138313700000000000000000000000000000000000000000000000000000000" - })", - https_metadata_response); - TestGetERC721Metadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, https_metadata_response, - mojom::ProviderError::kSuccess, ""); -} - -TEST_F(JsonRpcServiceUnitTest, GetERC1155Metadata) { - // Ensure GetERC1155Metadata passes the correct interface ID to - // GetEthTokenMetadata - SetTokenMetadataInterceptor(kERC1155MetadataInterfaceId, - mojom::kMainnetChainId, - R"({ - "jsonrpc":"2.0", - "id":1, - "result": "0x0000000000000000000000000000000000000000000000000000000000000001" - })", - R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002468747470733a2f2f696e76697369626c65667269656e64732e696f2f6170692f3138313700000000000000000000000000000000000000000000000000000000" - })", - https_metadata_response); - TestGetERC1155Metadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, https_metadata_response, - mojom::ProviderError::kSuccess, ""); -} - TEST_F(JsonRpcServiceUnitTest, GetERC721Balance) { bool callback_called = false; @@ -7222,305 +7022,6 @@ TEST_F(JsonRpcServiceUnitTest, EthGetLogs) { std::move(expected_logs), mojom::ProviderError::kSuccess, ""); } -TEST_F(JsonRpcServiceUnitTest, GetSolTokenMetadata) { - // Valid inputs should yield metadata JSON (happy case) - std::string get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "BGUN5hJf2zSue3S0I/fCq16UREt5NxP6mQdaq4cdGPs3Q8PG/R6KFUSgce78Nwk9Frvkd9bMbvTIKCRSDy88nZQgAAAAU1BFQ0lBTCBTQVVDRQAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAMgAAABodHRwczovL2JhZmtyZWlmNHd4NTR3anI3cGdmdWczd2xhdHIzbmZudHNmd25ndjZldXNlYmJxdWV6cnhlbmo2Y2s0LmlwZnMuZHdlYi5saW5rP2V4dD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgDAQIAAABlDeYSX9s0rnt0tCP3wqtelERLeTcT+pkHWquHHRj7NwFiDUmu+U8sXOOZQXL36xmknL+Zzd/z3uw2G0ERMo8Eth4BAgABAf8BAAEBoivvbAzLh2kD2cSu6IQIqGQDGeoh/UEDizyp6mLT1tUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", - "base64" - ], - "executable": false, - "lamports": 5616720, - "owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - "rentEpoch": 361 - } - }, - "id": 1 - })"; - const std::string valid_metadata_response = R"({ - "attributes": [ - { - "trait_type": "hair", - "value": "green & blue" - }, - { - "trait_type": "pontus", - "value": "no" - } - ], - "description": "", - "external_url": "", - "image": "https://bafkreiagsgqhjudpta6trhjuv5y2n2exsrhbkkprl64tvg2mftjsdm3vgi.ipfs.dweb.link?ext=png", - "name": "SPECIAL SAUCE", - "properties": { - "category": "image", - "creators": [ - { - "address": "7oUUEdptZnZVhSet4qobU9PtpPfiNUEJ8ftPnrC6YEaa", - "share": 98 - }, - { - "address": "tsU33UT3K2JTfLgHUo7hdzRhRe4wth885cqVbM8WLiq", - "share": 2 - } - ], - "files": [ - { - "type": "image/png", - "uri": "https://bafkreiagsgqhjudpta6trhjuv5y2n2exsrhbkkprl64tvg2mftjsdm3vgi.ipfs.dweb.link?ext=png" - } - ], - "maxSupply": 0 - }, - "seller_fee_basis_points": 1000, - "symbol": "" - })"; - auto network_url = GetNetwork(mojom::kSolanaMainnet, mojom::CoinType::SOL); - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata("5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", - valid_metadata_response, - mojom::SolanaProviderError::kSuccess, ""); - - // Invalid token_mint_address yields internal error. - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata("Invalid", "", - mojom::SolanaProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Non 200 getAccountInfo response of yields internal server error. - SetHTTPRequestTimeoutInterceptor(); - TestGetSolTokenMetadata("5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Invalid getAccountInfo response JSON yields internal error - SetSolTokenMetadataInterceptor( - network_url, "Invalid json response", - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata("5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Valid response JSON, invalid account info (missing result.value.owner - // field) info yields parse error - get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "BGUN5hJf2zSue3S0I/fCq16UREt5NxP6mQdaq4cdGPs3Q8PG/R6KFUSgce78Nwk9Frvkd9bMbvTIKCRSDy88nZQgAAAAU1BFQ0lBTCBTQVVDRQAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAMgAAABodHRwczovL2JhZmtyZWlmNHd4NTR3anI3cGdmdWczd2xhdHIzbmZudHNmd25ndjZldXNlYmJxdWV6cnhlbmo2Y2s0LmlwZnMuZHdlYi5saW5rP2V4dD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgDAQIAAABlDeYSX9s0rnt0tCP3wqtelERLeTcT+pkHWquHHRj7NwFiDUmu+U8sXOOZQXL36xmknL+Zzd/z3uw2G0ERMo8Eth4BAgABAf8BAAEBoivvbAzLh2kD2cSu6IQIqGQDGeoh/UEDizyp6mLT1tUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", - "base64" - ], - "executable": false, - "lamports": 5616720, - "rentEpoch": 361 - } - }, - "id": 1 - })"; - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata("5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // Valid response JSON, parsable account info, but invalid account info data - // (invalid base64) yields parse error - get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "*Invalid Base64*", - "base64" - ], - "executable": false, - "lamports": 5616720, - "owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - "rentEpoch": 361 - } - }, - "id": 1 - })"; - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata("5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // Valid response JSON, parsable account info, invalid account info data - // (valid base64, but invalid borsh encoded metadata) yields parse error - get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "d2hvb3BzIQ==", - "base64" - ], - "executable": false, - "lamports": 5616720, - "owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - "rentEpoch": 361 - } - }, - "id": 1 - })"; - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata("5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // Valid response JSON, parsable account info, invalid account info data - // (valid base64, valid borsh encoding, but when decoded the URI is not a - // valid URI) - get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "BGUN5hJf2zSue3S0I/fCq16UREt5NxP6mQdaq4cdGPs3Q8PG/R6KFUSgce78Nwk9Frvkd9bMbvTIKCRSDy88nZQgAAAAU1BFQ0lBTCBTQVVDRQAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAsAAABpbnZhbGlkIHVybOgDAQIAAABlDeYSX9s0rnt0tCP3wqtelERLeTcT+pkHWquHHRj7NwFiDUmu+U8sXOOZQXL36xmknL+Zzd/z3uw2G0ERMo8Eth4BAgABAf8BAAEBoivvbAzLh2kD2cSu6IQIqGQDGeoh/UEDizyp6mLT1tUA", - "base64" - ], - "executable": false, - "lamports": 5616720, - "owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - "rentEpoch": 361 - } - }, - "id": 1 - })"; - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata("5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); -} - -TEST_F(JsonRpcServiceUnitTest, GetEthTokenUri) { - // Invalid contract address input - TestGetEthTokenUri("", "0x1", mojom::kMainnetChainId, - kERC721MetadataInterfaceId, GURL(), - mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - - // Invalid token ID input - TestGetEthTokenUri("0x06012c8cf97BEaD5deAe237070F9587f8E7A266d", "", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, GURL(), - mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - - // Invalid chain ID input - TestGetEthTokenUri("0x06012c8cf97BEaD5deAe237070F9587f8E7A266d", "0x1", "", - kERC721MetadataInterfaceId, GURL(), - mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - - // Unknown interfaceID input - TestGetEthTokenUri("0x06012c8cf97BEaD5deAe237070F9587f8E7A266d", "0x1", - mojom::kMainnetChainId, "invalid interface", GURL(), - mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - - // Valid inputs but HTTP Timeout - SetHTTPRequestTimeoutInterceptor(); - TestGetEthTokenUri("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, GURL(), - mojom::ProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Valid inputs, request exceeds limit response - SetLimitExceededJsonErrorResponse(); - TestGetEthTokenUri("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, GURL(), - mojom::ProviderError::kLimitExceeded, - "Request exceeds defined limit"); - - // Valid inputs, invalid provider JSON - SetInvalidJsonInterceptor(); - TestGetEthTokenUri("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, GURL(), - mojom::ProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // Valid inputs, valid RPC response JSON, valid RLP encoding, invalid URI - SetInterceptor(GetNetwork(mojom::kMainnetChainId, mojom::CoinType::ETH), - "eth_call", "", R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b696e76616c69642075726c000000000000000000000000000000000000000000" - })"); - TestGetEthTokenUri("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, GURL(), - mojom::ProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // All valid - SetInterceptor(GetNetwork(mojom::kMainnetChainId, mojom::CoinType::ETH), - "eth_call", "", R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002468747470733a2f2f696e76697369626c65667269656e64732e696f2f6170692f3138313700000000000000000000000000000000000000000000000000000000" - })"); - TestGetEthTokenUri("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - GURL("https://invisiblefriends.io/api/1817"), - mojom::ProviderError::kSuccess, ""); -} - TEST_F(JsonRpcServiceUnitTest, GetEthNftStandard) { std::vector interfaces; // Empty interface IDs yields invalid params error diff --git a/components/brave_wallet/browser/nft_metadata_fetcher.cc b/components/brave_wallet/browser/nft_metadata_fetcher.cc deleted file mode 100644 index 85f20370cde..00000000000 --- a/components/brave_wallet/browser/nft_metadata_fetcher.cc +++ /dev/null @@ -1,365 +0,0 @@ -/* 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/. */ - -#include "brave/components/brave_wallet/browser/nft_metadata_fetcher.h" - -#include -#include -#include - -#include "base/base64.h" -#include "base/containers/span.h" -#include "base/containers/span_reader.h" -#include "base/json/json_writer.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" -#include "brave/components/brave_wallet/browser/eth_response_parser.h" -#include "brave/components/brave_wallet/browser/json_rpc_service.h" -#include "brave/components/brave_wallet/browser/network_manager.h" -#include "brave/components/brave_wallet/browser/solana_keyring.h" -#include "brave/components/ipfs/ipfs_utils.h" -#include "build/build_config.h" -#include "components/grit/brave_components_strings.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "ui/base/l10n/l10n_util.h" - -namespace { - -net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag() { - return net::DefineNetworkTrafficAnnotation("nft_metadata_fetcher", R"( - semantics { - sender: "NFT Metadata Fetcher" - description: - "This service is used to fetch NFT metadata " - "on behalf of the user interacting with the native Brave wallet." - trigger: - "Triggered by uses of the native Brave wallet." - data: - "NFT Metadata JSON." - destination: WEBSITE - } - policy { - cookies_allowed: NO - setting: - "You can enable or disable this feature on chrome://flags." - policy_exception_justification: - "Not implemented." - } - )"); -} - -} // namespace - -namespace brave_wallet { - -NftMetadataFetcher::NftMetadataFetcher( - scoped_refptr url_loader_factory, - JsonRpcService* json_rpc_service, - PrefService* prefs) - : api_request_helper_(new APIRequestHelper(GetNetworkTrafficAnnotationTag(), - url_loader_factory)), - json_rpc_service_(json_rpc_service), - prefs_(prefs), - weak_ptr_factory_(this) {} - -NftMetadataFetcher::~NftMetadataFetcher() = default; - -void NftMetadataFetcher::GetEthTokenMetadata( - const std::string& contract_address, - const std::string& token_id, - const std::string& chain_id, - const std::string& interface_id, - GetEthTokenMetadataCallback callback) { - auto network_url = json_rpc_service_->network_manager()->GetNetworkURL( - chain_id, mojom::CoinType::ETH); - if (!network_url.is_valid()) { - std::move(callback).Run( - "", "", mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - return; - } - - if (!EthAddress::IsValidAddress(contract_address)) { - std::move(callback).Run( - "", "", mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - return; - } - - auto internal_callback = - base::BindOnce(&NftMetadataFetcher::OnGetSupportsInterface, - weak_ptr_factory_.GetWeakPtr(), contract_address, - interface_id, token_id, chain_id, std::move(callback)); - - json_rpc_service_->GetSupportsInterface( - contract_address, interface_id, chain_id, std::move(internal_callback)); -} - -void NftMetadataFetcher::OnGetSupportsInterface( - const std::string& contract_address, - const std::string& interface_id, - const std::string& token_id, - const std::string& chain_id, - GetEthTokenMetadataCallback callback, - bool is_supported, - mojom::ProviderError error, - const std::string& error_message) { - if (error != mojom::ProviderError::kSuccess) { - std::move(callback).Run("", "", error, error_message); - return; - } - - if (!is_supported) { - std::move(callback).Run( - "", "", mojom::ProviderError::kMethodNotSupported, - l10n_util::GetStringUTF8(IDS_WALLET_METHOD_NOT_SUPPORTED_ERROR)); - return; - } - - auto internal_callback = - base::BindOnce(&NftMetadataFetcher::OnGetEthTokenUri, - weak_ptr_factory_.GetWeakPtr(), std::move(callback)); - - json_rpc_service_->GetEthTokenUri(chain_id, contract_address, token_id, - interface_id, std::move(internal_callback)); -} - -void NftMetadataFetcher::OnGetEthTokenUri(GetEthTokenMetadataCallback callback, - const GURL& uri, - mojom::ProviderError error, - const std::string& error_message) { - if (error != mojom::ProviderError::kSuccess) { - std::move(callback).Run("", "", error, error_message); - return; - } - - if (!uri.is_valid()) { - std::move(callback).Run( - "", "", mojom::ProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - return; - } - - auto internal_callback = - base::BindOnce(&NftMetadataFetcher::CompleteGetEthTokenMetadata, - weak_ptr_factory_.GetWeakPtr(), std::move(callback), uri); - FetchMetadata(uri, std::move(internal_callback)); -} - -void NftMetadataFetcher::FetchMetadata( - GURL url, - GetTokenMetadataIntermediateCallback callback) { - // Obtain JSON from the URL depending on the scheme. - // IPFS, HTTPS, and data URIs are supported. - // IPFS and HTTPS URIs require an additional request to fetch the metadata. - std::string metadata_json; - std::string_view scheme = url.scheme(); - if (scheme != url::kDataScheme && scheme != url::kHttpsScheme && - scheme != ipfs::kIPFSScheme) { - std::move(callback).Run( - "", static_cast(mojom::JsonRpcError::kInternalError), - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - return; - } - - if (scheme == url::kDataScheme) { - if (!eth::ParseDataURIAndExtractJSON(url, &metadata_json)) { - std::move(callback).Run( - "", static_cast(mojom::JsonRpcError::kParsingError), - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - return; - } - - // Sanitize JSON - api_request_helper::ParseJsonNonBlocking( - std::move(metadata_json), - base::BindOnce(&NftMetadataFetcher::OnSanitizeTokenMetadata, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); - return; - } - if (scheme == ipfs::kIPFSScheme && - !ipfs::TranslateIPFSURI(url, &url, false)) { - std::move(callback).Run( - "", static_cast(mojom::JsonRpcError::kParsingError), - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - return; - } - - auto internal_callback = - base::BindOnce(&NftMetadataFetcher::OnGetTokenMetadataPayload, - weak_ptr_factory_.GetWeakPtr(), std::move(callback)); - api_request_helper_->Request( - "GET", url, "", "", std::move(internal_callback), {}, - {.auto_retry_on_network_change = true, .enable_cache = true}); -} - -void NftMetadataFetcher::OnSanitizeTokenMetadata( - GetTokenMetadataIntermediateCallback callback, - api_request_helper::ValueOrError result) { - if (!result.has_value()) { - std::move(callback).Run( - "", static_cast(mojom::JsonRpcError::kParsingError), - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - return; - } - - // TODO(apaymyshev): parse metadata in wallet's backend - std::string json; - base::JSONWriter::Write(std::move(result).value(), &json); - std::move(callback).Run(std::move(json), 0, ""); // 0 is kSuccess -} - -void NftMetadataFetcher::OnGetTokenMetadataPayload( - GetTokenMetadataIntermediateCallback callback, - APIRequestResult api_request_result) { - mojom::ProviderErrorUnionPtr error; - if (!api_request_result.Is2XXResponseCode()) { - std::move(callback).Run( - "", static_cast(mojom::JsonRpcError::kInternalError), - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - return; - } - - // Invalid JSON becomes an empty string after sanitization - if (api_request_result.value_body().is_none()) { - std::move(callback).Run( - "", static_cast(mojom::JsonRpcError::kParsingError), - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - return; - } - - // TODO(supermassive): Refactor and remove SerializeBodyToString(). - std::move(callback).Run(api_request_result.SerializeBodyToString(), 0, - ""); // 0 is kSuccess -} - -void NftMetadataFetcher::CompleteGetEthTokenMetadata( - GetEthTokenMetadataCallback callback, - const GURL& uri, - const std::string& response, - int error, - const std::string& error_message) { - mojom::ProviderError mojo_err = static_cast(error); - if (!mojom::IsKnownEnumValue(mojo_err)) { - mojo_err = mojom::ProviderError::kUnknown; - } - std::move(callback).Run(uri.spec(), response, mojo_err, error_message); -} - -void NftMetadataFetcher::GetSolTokenMetadata( - const std::string& chain_id, - const std::string& token_mint_address, - GetSolTokenMetadataCallback callback) { - // Derive metadata PDA for the NFT accounts - std::optional associated_metadata_account = - SolanaKeyring::GetAssociatedMetadataAccount(token_mint_address); - if (!associated_metadata_account) { - std::move(callback).Run( - "", "", mojom::SolanaProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - return; - } - - auto internal_callback = - base::BindOnce(&NftMetadataFetcher::OnGetSolanaAccountInfoTokenMetadata, - weak_ptr_factory_.GetWeakPtr(), std::move(callback)); - json_rpc_service_->GetSolanaAccountInfo( - chain_id, *associated_metadata_account, std::move(internal_callback)); -} - -void NftMetadataFetcher::OnGetSolanaAccountInfoTokenMetadata( - GetSolTokenMetadataCallback callback, - std::optional account_info, - mojom::SolanaProviderError error, - const std::string& error_message) { - if (error != mojom::SolanaProviderError::kSuccess || !account_info) { - std::move(callback).Run("", "", error, error_message); - return; - } - - std::optional> metadata = - base::Base64Decode(account_info->data); - - if (!metadata) { - std::move(callback).Run("", "", mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - return; - } - - std::optional url = DecodeMetadataUri(*metadata); - if (!url || !url.value().is_valid()) { - std::move(callback).Run("", "", mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - return; - } - - FetchMetadata(*url, - base::BindOnce(&NftMetadataFetcher::CompleteGetSolTokenMetadata, - weak_ptr_factory_.GetWeakPtr(), *url, - std::move(callback))); -} - -void NftMetadataFetcher::CompleteGetSolTokenMetadata( - const GURL& uri, - GetSolTokenMetadataCallback callback, - const std::string& response, - int error, - const std::string& error_message) { - mojom::SolanaProviderError mojo_err = - static_cast(error); - if (!mojom::IsKnownEnumValue(mojo_err)) { - mojo_err = mojom::SolanaProviderError::kUnknown; - } - std::move(callback).Run(uri.spec(), response, mojo_err, error_message); -} - -// static -// Expects a the bytes of a Borsh encoded Metadata struct (see -// https://docs.rs/crate/spl-token-metadata/0.0.1/source/src/state.rs#93-104 -// and returns the URI string in of the nested Data struct (see -// https://docs.rs/crate/spl-token-metadata/0.0.1/source/src/state.rs#78-89) -// as a GURL. -std::optional NftMetadataFetcher::DecodeMetadataUri( - base::span data) { - base::SpanReader span_reader(data); - if (!span_reader.Skip( - /* Skip first byte for metadata.key */ 1u + - /* Skip next 32 bytes for `metadata.update_authority` */ 32u + - /* Skip next 32 bytes for `metadata.mint` */ 32u)) { - return std::nullopt; - } - - // Skip next field, metadata.data.name, a string - // whose length is represented by a leading 32 bit integer - uint32_t name_length = 0; - if (!span_reader.ReadU32LittleEndian(name_length)) { - return std::nullopt; - } - if (!span_reader.Skip(name_length)) { - return std::nullopt; - } - - // Skip next field, `metadata.data.symbol`, a string - // whose length is represented by a leading 32 bit integer - uint32_t symbol_length = 0; - if (!span_reader.ReadU32LittleEndian(symbol_length)) { - return std::nullopt; - } - if (!span_reader.Skip(symbol_length)) { - return std::nullopt; - } - - // Parse next field, metadata.data.uri, a string - uint32_t uri_length = 0; - if (!span_reader.ReadU32LittleEndian(uri_length)) { - return std::nullopt; - } - auto uri_bytes = span_reader.Read(uri_length); - if (!uri_bytes) { - return std::nullopt; - } - return GURL(base::as_string_view(*uri_bytes)); -} - -} // namespace brave_wallet diff --git a/components/brave_wallet/browser/nft_metadata_fetcher.h b/components/brave_wallet/browser/nft_metadata_fetcher.h deleted file mode 100644 index 33589d99a81..00000000000 --- a/components/brave_wallet/browser/nft_metadata_fetcher.h +++ /dev/null @@ -1,112 +0,0 @@ -/* 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/. */ - -#ifndef BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_NFT_METADATA_FETCHER_H_ -#define BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_NFT_METADATA_FETCHER_H_ - -#include -#include -#include - -#include "base/containers/span.h" -#include "base/gtest_prod_util.h" -#include "base/memory/raw_ptr.h" -#include "base/memory/weak_ptr.h" -#include "brave/components/api_request_helper/api_request_helper.h" -#include "brave/components/brave_wallet/browser/json_rpc_service.h" - -class PrefService; - -namespace brave_wallet { - -class JsonRpcService; - -class NftMetadataFetcher { - public: - NftMetadataFetcher( - scoped_refptr url_loader_factory, - JsonRpcService* json_rpc_service, - PrefService* prefs); - - NftMetadataFetcher(const NftMetadataFetcher&) = delete; - NftMetadataFetcher& operator=(NftMetadataFetcher&) = delete; - ~NftMetadataFetcher(); - - using APIRequestHelper = api_request_helper::APIRequestHelper; - using APIRequestResult = api_request_helper::APIRequestResult; - using GetEthTokenMetadataCallback = - base::OnceCallback; - void GetEthTokenMetadata(const std::string& contract_address, - const std::string& token_id, - const std::string& chain_id, - const std::string& interface_id, - GetEthTokenMetadataCallback callback); - using GetSolTokenMetadataCallback = - base::OnceCallback; - void GetSolTokenMetadata(const std::string& chain_id, - const std::string& token_mint_address, - GetSolTokenMetadataCallback callback); - using GetTokenMetadataIntermediateCallback = - base::OnceCallback; - void FetchMetadata(GURL url, GetTokenMetadataIntermediateCallback callback); - - private: - void OnGetSupportsInterface(const std::string& contract_address, - const std::string& interface_id, - const std::string& token_id, - const std::string& chain_id, - // const GURL& network_url, - GetEthTokenMetadataCallback callback, - bool is_supported, - mojom::ProviderError error, - const std::string& error_message); - - void OnGetEthTokenUri(GetEthTokenMetadataCallback callback, - const GURL& uri, - mojom::ProviderError error, - const std::string& error_message); - void OnSanitizeTokenMetadata(GetTokenMetadataIntermediateCallback callback, - api_request_helper::ValueOrError result); - void OnGetTokenMetadataPayload(GetTokenMetadataIntermediateCallback callback, - APIRequestResult api_request_result); - void OnGetSolanaAccountInfoTokenMetadata( - GetSolTokenMetadataCallback callback, - std::optional account_info, - mojom::SolanaProviderError error, - const std::string& error_message); - void CompleteGetEthTokenMetadata(GetEthTokenMetadataCallback callback, - const GURL& uri, - const std::string& response, - int error, - const std::string& error_message); - void CompleteGetSolTokenMetadata(const GURL& uri, - GetSolTokenMetadataCallback callback, - const std::string& response, - int error, - const std::string& error_message); - - friend class NftMetadataFetcherUnitTest; - FRIEND_TEST_ALL_PREFIXES(NftMetadataFetcherUnitTest, DecodeMetadataUri); - - static std::optional DecodeMetadataUri(base::span data); - - scoped_refptr url_loader_factory_; - std::unique_ptr api_request_helper_; - raw_ptr json_rpc_service_ = nullptr; - raw_ptr prefs_ = nullptr; - base::WeakPtrFactory weak_ptr_factory_; -}; - -} // namespace brave_wallet - -#endif // BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_NFT_METADATA_FETCHER_H_ diff --git a/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc b/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc deleted file mode 100644 index 7cbc330346f..00000000000 --- a/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc +++ /dev/null @@ -1,966 +0,0 @@ -/* 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/. */ - -#include "brave/components/brave_wallet/browser/nft_metadata_fetcher.h" - -#include -#include -#include - -#include "base/base64.h" -#include "base/containers/span.h" -#include "base/test/bind.h" -#include "base/test/task_environment.h" -#include "base/test/values_test_util.h" -#include "brave/components/brave_wallet/browser/brave_wallet_constants.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" -#include "brave/components/brave_wallet/browser/json_rpc_service.h" -#include "brave/components/brave_wallet/browser/network_manager.h" -#include "brave/components/brave_wallet/browser/pref_names.h" -#include "brave/components/brave_wallet/common/hash_utils.h" -#include "components/sync_preferences/testing_pref_service_syncable.h" -#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" -#include "services/network/test/test_url_loader_factory.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/l10n/l10n_util.h" - -namespace brave_wallet { - -namespace { - -constexpr char https_metadata_response[] = R"({ - "attributes": [ - { - "trait_type": "Feet", - "value": "Green Shoes" - }, - { - "trait_type": "Legs", - "value": "Tan Pants" - }, - { - "trait_type": "Suspenders", - "value": "White Suspenders" - }, - { - "trait_type": "Upper Body", - "value": "Indigo Turtleneck" - }, - { - "trait_type": "Sleeves", - "value": "Long Sleeves" - }, - { - "trait_type": "Hat", - "value": "Yellow / Blue Pointy Beanie" - }, - { - "trait_type": "Eyes", - "value": "White Nerd Glasses" - }, - { - "trait_type": "Mouth", - "value": "Toothpick" - }, - { - "trait_type": "Ears", - "value": "Bing Bong Stick" - }, - { - "trait_type": "Right Arm", - "value": "Swinging" - }, - { - "trait_type": "Left Arm", - "value": "Diamond Hand" - }, - { - "trait_type": "Background", - "value": "Blue" - } - ], - "description": "5,000 animated Invisible Friends hiding in the metaverse. A collection by Markus Magnusson & Random Character Collective.", - "image": "https://rcc.mypinata.cloud/ipfs/QmXmuSenZRnofhGMz2NyT3Yc4Zrty1TypuiBKDcaBsNw9V/1817.gif", - "name": "Invisible Friends #1817" - })"; - -} // namespace - -class NftMetadataFetcherUnitTest : public testing::Test { - public: - NftMetadataFetcherUnitTest() = default; - void SetUp() override { - brave_wallet::RegisterProfilePrefs(prefs_.registry()); - network_manager_ = std::make_unique(&prefs_); - json_rpc_service_ = std::make_unique( - url_loader_factory_.GetSafeWeakWrapper(), network_manager_.get(), - &prefs_, nullptr); - nft_metadata_fetcher_ = std::make_unique( - url_loader_factory_.GetSafeWeakWrapper(), json_rpc_service_.get(), - GetPrefs()); - } - - PrefService* GetPrefs() { return &prefs_; } - - void TestFetchMetadata(const GURL& url, - const std::string& expected_response, - int expected_error, - const std::string& expected_error_message) { - base::RunLoop run_loop; - nft_metadata_fetcher_->FetchMetadata( - url, - base::BindLambdaForTesting([&](const std::string& response, int error, - const std::string& error_message) { - if (response.empty()) { - EXPECT_EQ(response, expected_response); - } else { - EXPECT_EQ(base::test::ParseJson(response), - base::test::ParseJson(expected_response)); - } - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - run_loop.Quit(); - })); - run_loop.Run(); - } - - void TestGetEthTokenMetadata(const std::string& contract, - const std::string& token_id, - const std::string& chain_id, - const std::string& interface_id, - const std::string& expected_response, - mojom::ProviderError expected_error, - const std::string& expected_error_message) { - base::RunLoop run_loop; - nft_metadata_fetcher_->GetEthTokenMetadata( - contract, token_id, chain_id, interface_id, - base::BindLambdaForTesting( - [&](const std::string& url, const std::string& response, - mojom::ProviderError error, const std::string& error_message) { - if (response.empty()) { - EXPECT_EQ(response, expected_response); - } else { - EXPECT_EQ(base::test::ParseJson(response), - base::test::ParseJson(expected_response)); - } - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - run_loop.Quit(); - })); - run_loop.Run(); - } - - void TestGetSolTokenMetadata(const std::string& chain_id, - const std::string& token_mint_address, - const std::string& expected_response, - mojom::SolanaProviderError expected_error, - const std::string& expected_error_message) { - base::RunLoop loop; - nft_metadata_fetcher_->GetSolTokenMetadata( - chain_id, token_mint_address, - base::BindLambdaForTesting([&](const std::string& token_url, - const std::string& response, - mojom::SolanaProviderError error, - const std::string& error_message) { - if (response.empty()) { - EXPECT_EQ(response, expected_response); - } else { - EXPECT_EQ(base::test::ParseJson(response), - base::test::ParseJson(expected_response)); - } - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - loop.Quit(); - })); - loop.Run(); - } - - void SetInterceptor(const GURL& expected_url, const std::string& content) { - url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( - [&, expected_url, content](const network::ResourceRequest& request) { - EXPECT_EQ(request.url, expected_url); - url_loader_factory_.ClearResponses(); - url_loader_factory_.AddResponse(request.url.spec(), content); - })); - } - - void SetInvalidJsonInterceptor() { - url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( - [&](const network::ResourceRequest& request) { - url_loader_factory_.ClearResponses(); - url_loader_factory_.AddResponse(request.url.spec(), "Answer is 42"); - })); - } - - void SetHTTPRequestTimeoutInterceptor() { - url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( - [&](const network::ResourceRequest& request) { - url_loader_factory_.ClearResponses(); - url_loader_factory_.AddResponse(request.url.spec(), "", - net::HTTP_REQUEST_TIMEOUT); - })); - } - - void SetTokenMetadataInterceptor( - const std::string& interface_id, - const std::string& chain_id, - const std::string& supports_interface_provider_response, - const std::string& token_uri_provider_response = "", - const std::string& metadata_response = "", - net::HttpStatusCode supports_interface_status = net::HTTP_OK, - net::HttpStatusCode token_uri_status = net::HTTP_OK, - net::HttpStatusCode metadata_status = net::HTTP_OK) { - GURL network_url = - network_manager_->GetNetworkURL(chain_id, mojom::CoinType::ETH); - ASSERT_TRUE(network_url.is_valid()); - url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( - [&, interface_id, supports_interface_provider_response, - token_uri_provider_response, metadata_response, - supports_interface_status, token_uri_status, metadata_status, - network_url](const network::ResourceRequest& request) { - url_loader_factory_.ClearResponses(); - if (request.method == - "POST") { // An eth_call, either to supportsInterface or tokenURI - std::string_view request_string(request.request_body->elements() - ->at(0) - .As() - .AsStringPiece()); - bool is_supports_interface_req = - request_string.find(GetFunctionHash( - "supportsInterface(bytes4)")) != std::string::npos; - if (is_supports_interface_req) { - ASSERT_NE(request_string.find(interface_id.substr(2)), - std::string::npos); - EXPECT_EQ(request.url.spec(), network_url); - url_loader_factory_.AddResponse( - network_url.spec(), supports_interface_provider_response, - supports_interface_status); - return; - } else { - std::string function_hash; - if (interface_id == kERC721MetadataInterfaceId) { - function_hash = GetFunctionHash("tokenURI(uint256)"); - } else { - function_hash = GetFunctionHash("uri(uint256)"); - } - ASSERT_NE(request_string.find(function_hash), std::string::npos); - url_loader_factory_.AddResponse(network_url.spec(), - token_uri_provider_response, - token_uri_status); - return; - } - } else { // A HTTP GET to fetch the metadata json from the web - url_loader_factory_.AddResponse(request.url.spec(), - metadata_response, metadata_status); - return; - } - })); - } - - void SetSolTokenMetadataInterceptor( - const GURL& expected_rpc_url, - const std::string& get_account_info_response, - const GURL& expected_metadata_url, - const std::string& metadata_response) { - ASSERT_TRUE(expected_rpc_url.is_valid()); - ASSERT_TRUE(expected_metadata_url.is_valid()); - url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( - [&, expected_rpc_url, get_account_info_response, expected_metadata_url, - metadata_response](const network::ResourceRequest& request) { - url_loader_factory_.AddResponse(expected_rpc_url.spec(), - get_account_info_response); - url_loader_factory_.AddResponse(expected_metadata_url.spec(), - metadata_response); - })); - } - - protected: - base::test::TaskEnvironment task_environment_; - sync_preferences::TestingPrefServiceSyncable prefs_; - network::TestURLLoaderFactory url_loader_factory_; - std::unique_ptr network_manager_; - std::unique_ptr json_rpc_service_; - std::unique_ptr nft_metadata_fetcher_; -}; - -TEST_F(NftMetadataFetcherUnitTest, FetchMetadata) { - // Invalid URL yields internal error - TestFetchMetadata(GURL("invalid url"), "", - static_cast(mojom::JsonRpcError::kInternalError), - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Unsupported scheme yields internal error - TestFetchMetadata(GURL("file://host/path"), "", - static_cast(mojom::JsonRpcError::kInternalError), - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Data URL with unsupported mime type yields parsing error - TestFetchMetadata( - GURL("data:text/" - "csv;base64,eyJpbWFnZV91cmwiOiAgImh0dHBzOi8vZXhhbXBsZS5jb20ifQ=="), - "", static_cast(mojom::JsonRpcError::kParsingError), - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // Valid URL but that results in HTTP timeout yields internal error - SetHTTPRequestTimeoutInterceptor(); - TestFetchMetadata(GURL("https://example.com"), "", - static_cast(mojom::JsonRpcError::kInternalError), - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Valid URL but invalid json response yields parsing error - SetInvalidJsonInterceptor(); - TestFetchMetadata(GURL("https://example.com"), "", - static_cast(mojom::JsonRpcError::kParsingError), - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // All valid yields response json set via interceptor - GURL url = GURL("https://example.com"); - const std::string& metadata_json = - R"({"image_url":"https://example.com/image.jpg"})"; - SetInterceptor(url, metadata_json); - TestFetchMetadata(url, metadata_json, - static_cast(mojom::ProviderError::kSuccess), ""); -} - -TEST_F(NftMetadataFetcherUnitTest, GetEthTokenMetadata) { - // Decoded result is `https://invisiblefriends.io/api/1817` - const std::string https_token_uri_response = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002468747470733a2f2f696e76697369626c65667269656e64732e696f2f6170692f3138313700000000000000000000000000000000000000000000000000000000" - })"; - - // Decoded result is `http://invisiblefriends.io/api/1` - const std::string http_token_uri_response = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020687474703a2f2f696e76697369626c65667269656e64732e696f2f6170692f31" - })"; - - // Decoded result is - // `data:application/json;base64,eyJhdHRyaWJ1dGVzIjoiIiwiZGVzY3JpcHRpb24iOiJOb24gZnVuZ2libGUgbGlvbiIsImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhacFpYZENiM2c5SWpBZ01DQTFNREFnTlRBd0lqNDhjR0YwYUNCa1BTSWlMejQ4TDNOMlp6ND0iLCJuYW1lIjoiTkZMIn0=` - // Decoded base64 is `{"attributes":"","description":"Non fungible - // lion","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MDAgNTAwIj4d8cGF0aCBkPSIiLz48L3N2Zz4=","name":"NFL"}` - const std::string data_token_uri_response = R"({ - "jsonrpc":"2.0", - "id":1, - "result": "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000135646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c65794a686448527961574a316447567a496a6f69496977695a47567a59334a7063485270623234694f694a4f623234675a6e56755a326c696247556762476c7662694973496d6c745957646c496a6f695a474630595470706257466e5a53397a646d6372654731734f324a68633255324e43785153453479576e6c434e474a586548566a656a4270595568534d474e4562335a4d4d32517a5a486b314d3031354e585a6a62574e3254577042643031444f58706b62574e7053556861634670595a454e694d326335535770425a3031445154464e5245466e546c524264306c714e44686a5230597759554e436131425453576c4d656a513454444e4f4d6c70364e4430694c434a755957316c496a6f69546b5a4d496e303d0000000000000000000000" - })"; - - // Decoded result is - // `data:application/json;base64,eyJuYW1lIjoiTkZMIiwgImRlc2NyaXB0aW9uIjoiTm9uIGZ1bmdpYmxlIGxpb24iLCAiYXR0cmlidXRlcyI6IiIsICJpbWFnZSI6IiI=` - // Decoded base64 is `{"name":"NFL", "description":"Non fungible lion", - // "attributes":"", "image":""` - const std::string data_token_uri_response_invalid_json = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000085646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c65794a755957316c496a6f69546b5a4d49697767496d526c63324e796158423061573975496a6f69546d397549475a31626d6470596d786c49477870623234694c43416959585230636d6c696458526c637949364969497349434a706257466e5a5349364969493d000000000000000000000000000000000000000000000000000000" - })"; - - // Decoded result is `data:application/json;base64,` - const std::string data_token_uri_response_empty_string = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001d646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000" - })"; - - // Decoded result is `true` - const std::string interface_supported_response = R"({ - "jsonrpc":"2.0", - "id":1, - "result": "0x0000000000000000000000000000000000000000000000000000000000000001" - })"; - const std::string exceeds_limit_json = R"({ - "jsonrpc":"2.0", - "id":1, - "error": { - "code":-32005, - "message": "Request exceeds defined limit" - } - })"; - - // Decoded result is `false` - const std::string interface_not_supported_response = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000000" - })"; - const std::string invalid_json = - "It might make sense just to get some in case it catches on"; - - // Decoded result is - // `ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/1817` - const std::string ipfs_token_uri_response = R"({ - "jsonrpc":"2.0", - "id":1, - "result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003a697066733a2f2f516d65536a53696e4870506e6d586d73704d6a776958794e367a533445397a63636172694752336a7863615774712f31383137000000000000" - })"; - const std::string ipfs_metadata_response = R"({ - "attributes": [ - { - "trait_type": "Mouth", - "value": "Bored Cigarette" - }, - { - "trait_type": "Fur", - "value": "Gray" - }, - { - "trait_type": "Background", - "value": "Aquamarine" - }, - { - "trait_type": "Clothes", - "value": "Tuxedo Tee" - }, - { - "trait_type": "Hat", - "value": "Bayc Hat Black" - }, - { - "trait_type": "Eyes", - "value": "Coins" - } - ], - "image": "ipfs://QmQ82uDT3JyUMsoZuaFBYuEucF654CYE5ktPUrnA5d4VDH" - })"; - - // Invalid inputs - // (1/3) Invalid contract address - TestGetEthTokenMetadata( - "", "0x1", mojom::kMainnetChainId, kERC721MetadataInterfaceId, "", - mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - - // (2/3) Invalid token ID - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, https_token_uri_response, - https_metadata_response); - TestGetEthTokenMetadata( - "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d", "", mojom::kMainnetChainId, - kERC721MetadataInterfaceId, "", mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - - // (3/3) Invalid chain ID - TestGetEthTokenMetadata( - "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d", "0x1", "", - kERC721MetadataInterfaceId, "", mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - - // Mismatched - // (4/4) Unknown interfaceID - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, https_token_uri_response, - https_metadata_response); - TestGetEthTokenMetadata( - "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d", "0x1", - mojom::kMainnetChainId, "invalid interface", "", - mojom::ProviderError::kInvalidParams, - l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); - - // Valid inputs - // (1/3) HTTP URI - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, https_token_uri_response, - https_metadata_response); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - https_metadata_response, - mojom::ProviderError::kSuccess, ""); - - // (2/3) IPFS URI - SetTokenMetadataInterceptor(kERC721MetadataInterfaceId, - mojom::kLocalhostChainId, - interface_supported_response, - ipfs_token_uri_response, ipfs_metadata_response); - TestGetEthTokenMetadata("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "0x719", - mojom::kLocalhostChainId, kERC721MetadataInterfaceId, - ipfs_metadata_response, - mojom::ProviderError::kSuccess, ""); - - // (3/3) Data URI - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, data_token_uri_response); - TestGetEthTokenMetadata("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - R"({ - "attributes": "", - "description": "Non fungible lion", - "image": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MDAgNTAwIj48cGF0aCBkPSIiLz48L3N2Zz4=", - "name": "NFL" - })", - mojom::ProviderError::kSuccess, ""); - - // Invalid supportsInterface response - // (1/4) Timeout - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, https_token_uri_response, "", - net::HTTP_REQUEST_TIMEOUT); - TestGetEthTokenMetadata("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // (2/4) Invalid JSON - SetTokenMetadataInterceptor(kERC721MetadataInterfaceId, - mojom::kMainnetChainId, invalid_json); - TestGetEthTokenMetadata("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // (3/4) Request exceeds provider limit - SetTokenMetadataInterceptor(kERC721MetadataInterfaceId, - mojom::kMainnetChainId, exceeds_limit_json); - TestGetEthTokenMetadata("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kLimitExceeded, - "Request exceeds defined limit"); - - // (4/4) Interface not supported - SetTokenMetadataInterceptor(kERC721MetadataInterfaceId, - mojom::kMainnetChainId, - interface_not_supported_response); - TestGetEthTokenMetadata( - "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, "", - mojom::ProviderError::kMethodNotSupported, - l10n_util::GetStringUTF8(IDS_WALLET_METHOD_NOT_SUPPORTED_ERROR)); - - // Invalid tokenURI response (6 total) - // (1/6) Timeout - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, https_token_uri_response, "", net::HTTP_OK, - net::HTTP_REQUEST_TIMEOUT); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // (2/6) Invalid Provider JSON - SetTokenMetadataInterceptor(kERC721MetadataInterfaceId, - mojom::kMainnetChainId, - interface_supported_response, invalid_json); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // (3/6) Invalid JSON in data URI - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, data_token_uri_response_invalid_json); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // (4/6) Empty string as JSON in data URI - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, data_token_uri_response_empty_string); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // (5/6) Request exceeds limit - SetTokenMetadataInterceptor(kERC721MetadataInterfaceId, - mojom::kMainnetChainId, - interface_supported_response, exceeds_limit_json); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kLimitExceeded, - "Request exceeds defined limit"); - - // (6/6) URI scheme is not suported (HTTP) - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, http_token_uri_response); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Invalid metadata response (2 total) - // (1/2) Timeout - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, https_token_uri_response, - https_metadata_response, net::HTTP_OK, net::HTTP_OK, - net::HTTP_REQUEST_TIMEOUT); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // (2/2) Invalid JSON - SetTokenMetadataInterceptor( - kERC721MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, ipfs_token_uri_response, invalid_json); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC721MetadataInterfaceId, - "", mojom::ProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // ERC1155 - SetTokenMetadataInterceptor( - kERC1155MetadataInterfaceId, mojom::kMainnetChainId, - interface_supported_response, https_token_uri_response, - https_metadata_response); - TestGetEthTokenMetadata("0x59468516a8259058bad1ca5f8f4bff190d30e066", "0x719", - mojom::kMainnetChainId, kERC1155MetadataInterfaceId, - https_metadata_response, - mojom::ProviderError::kSuccess, ""); -} - -TEST_F(NftMetadataFetcherUnitTest, GetSolTokenMetadata) { - // Valid inputs should yield metadata JSON (happy case) - std::string get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "BGUN5hJf2zSue3S0I/fCq16UREt5NxP6mQdaq4cdGPs3Q8PG/R6KFUSgce78Nwk9Frvkd9bMbvTIKCRSDy88nZQgAAAAU1BFQ0lBTCBTQVVDRQAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAMgAAABodHRwczovL2JhZmtyZWlmNHd4NTR3anI3cGdmdWczd2xhdHIzbmZudHNmd25ndjZldXNlYmJxdWV6cnhlbmo2Y2s0LmlwZnMuZHdlYi5saW5rP2V4dD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgDAQIAAABlDeYSX9s0rnt0tCP3wqtelERLeTcT+pkHWquHHRj7NwFiDUmu+U8sXOOZQXL36xmknL+Zzd/z3uw2G0ERMo8Eth4BAgABAf8BAAEBoivvbAzLh2kD2cSu6IQIqGQDGeoh/UEDizyp6mLT1tUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", - "base64" - ], - "executable": false, - "lamports": 5616720, - "owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - "rentEpoch": 361 - } - }, - "id": 1 - })"; - const std::string valid_metadata_response = R"({ - "attributes": [ - { - "trait_type": "hair", - "value": "green & blue" - }, - { - "trait_type": "pontus", - "value": "no" - } - ], - "description": "", - "external_url": "", - "image": "https://bafkreiagsgqhjudpta6trhjuv5y2n2exsrhbkkprl64tvg2mftjsdm3vgi.ipfs.dweb.link?ext=png", - "name": "SPECIAL SAUCE", - "properties": { - "category": "image", - "creators": [ - { - "address": "7oUUEdptZnZVhSet4qobU9PtpPfiNUEJ8ftPnrC6YEaa", - "share": 98 - }, - { - "address": "tsU33UT3K2JTfLgHUo7hdzRhRe4wth885cqVbM8WLiq", - "share": 2 - } - ], - "files": [ - { - "type": "image/png", - "uri": "https://bafkreiagsgqhjudpta6trhjuv5y2n2exsrhbkkprl64tvg2mftjsdm3vgi.ipfs.dweb.link?ext=png" - } - ], - "maxSupply": 0 - }, - "seller_fee_basis_points": 1000, - "symbol": "" - })"; - auto network_url = network_manager_->GetNetworkURL(mojom::kSolanaMainnet, - mojom::CoinType::SOL); - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata( - mojom::kSolanaMainnet, "5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", - valid_metadata_response, mojom::SolanaProviderError::kSuccess, ""); - - // Invalid token_mint_address yields internal error. - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata(mojom::kSolanaMainnet, "Invalid", "", - mojom::SolanaProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Non 200 getAccountInfo response of yields internal server error. - SetHTTPRequestTimeoutInterceptor(); - TestGetSolTokenMetadata(mojom::kSolanaMainnet, - "5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Invalid getAccountInfo response JSON yields internal error - SetSolTokenMetadataInterceptor( - network_url, "Invalid json response", - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata(mojom::kSolanaMainnet, - "5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kInternalError, - l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); - - // Valid response JSON, invalid account info (missing result.value.owner - // field) info yields parse error - get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "BGUN5hJf2zSue3S0I/fCq16UREt5NxP6mQdaq4cdGPs3Q8PG/R6KFUSgce78Nwk9Frvkd9bMbvTIKCRSDy88nZQgAAAAU1BFQ0lBTCBTQVVDRQAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAMgAAABodHRwczovL2JhZmtyZWlmNHd4NTR3anI3cGdmdWczd2xhdHIzbmZudHNmd25ndjZldXNlYmJxdWV6cnhlbmo2Y2s0LmlwZnMuZHdlYi5saW5rP2V4dD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgDAQIAAABlDeYSX9s0rnt0tCP3wqtelERLeTcT+pkHWquHHRj7NwFiDUmu+U8sXOOZQXL36xmknL+Zzd/z3uw2G0ERMo8Eth4BAgABAf8BAAEBoivvbAzLh2kD2cSu6IQIqGQDGeoh/UEDizyp6mLT1tUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", - "base64" - ], - "executable": false, - "lamports": 5616720, - "rentEpoch": 361 - } - }, - "id": 1 - })"; - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata(mojom::kSolanaMainnet, - "5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // Valid response JSON, parsable account info, but invalid account info data - // (invalid base64) yields parse error - get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "*Invalid Base64*", - "base64" - ], - "executable": false, - "lamports": 5616720, - "owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - "rentEpoch": 361 - } - }, - "id": 1 - })"; - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata(mojom::kSolanaMainnet, - "5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // Valid response JSON, parsable account info, invalid account info data - // (valid base64, but invalid borsh encoded metadata) yields parse error - get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "d2hvb3BzIQ==", - "base64" - ], - "executable": false, - "lamports": 5616720, - "owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - "rentEpoch": 361 - } - }, - "id": 1 - })"; - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata(mojom::kSolanaMainnet, - "5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); - - // Valid response JSON, parsable account info, invalid account info data - // (valid base64, valid borsh encoding, but when decoded the URI is not a - // valid URI) - get_account_info_response = R"({ - "jsonrpc": "2.0", - "result": { - "context": { - "apiVersion": "1.13.3", - "slot": 161038284 - }, - "value": { - "data": [ - "BGUN5hJf2zSue3S0I/fCq16UREt5NxP6mQdaq4cdGPs3Q8PG/R6KFUSgce78Nwk9Frvkd9bMbvTIKCRSDy88nZQgAAAAU1BFQ0lBTCBTQVVDRQAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAsAAABpbnZhbGlkIHVybOgDAQIAAABlDeYSX9s0rnt0tCP3wqtelERLeTcT+pkHWquHHRj7NwFiDUmu+U8sXOOZQXL36xmknL+Zzd/z3uw2G0ERMo8Eth4BAgABAf8BAAEBoivvbAzLh2kD2cSu6IQIqGQDGeoh/UEDizyp6mLT1tUA", - "base64" - ], - "executable": false, - "lamports": 5616720, - "owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", - "rentEpoch": 361 - } - }, - "id": 1 - })"; - SetSolTokenMetadataInterceptor( - network_url, get_account_info_response, - GURL("https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="), - valid_metadata_response); - TestGetSolTokenMetadata(mojom::kSolanaMainnet, - "5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh", "", - mojom::SolanaProviderError::kParsingError, - l10n_util::GetStringUTF8(IDS_WALLET_PARSING_ERROR)); -} - -TEST_F(NftMetadataFetcherUnitTest, DecodeMetadataUri) { - // Valid borsh encoding and URI yields expected URI - std::vector uri_borsh_encoded = { - 4, 101, 13, 230, 18, 95, 219, 52, 174, 123, 116, 180, 35, 247, 194, 171, - 94, 148, 68, 75, 121, 55, 19, 250, 153, 7, 90, 171, 135, 29, 24, 251, 55, - 67, 195, 198, 253, 30, 138, 21, 68, 160, 113, 238, 252, 55, 9, 61, 22, - 187, 228, 119, 214, 204, 110, 244, 200, 40, 36, 82, 15, 47, 60, 157, 148, - 32, 0, 0, 0, 83, 80, 69, 67, 73, 65, 76, 32, 83, 65, 85, 67, 69, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - // the next 204 bytes encode the URI string - 200, 0, 0, 0, // uri length ends here - 104, 116, 116, 112, 115, 58, 47, 47, 98, 97, 102, 107, 114, 101, 105, 102, - 52, 119, 120, 53, 52, 119, 106, 114, 55, 112, 103, 102, 117, 103, 51, 119, - 108, 97, 116, 114, 51, 110, 102, 110, 116, 115, 102, 119, 110, 103, 118, - 54, 101, 117, 115, 101, 98, 98, 113, 117, 101, 122, 114, 120, 101, 110, - 106, 54, 99, 107, 52, 46, 105, 112, 102, 115, 46, 100, 119, 101, 98, 46, - 108, 105, 110, 107, 63, 101, 120, 116, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, // uri payload ends here - 232, 3, 0, 0, 1, 1, 255, 1, 0, 1, 1, 162, 43, 239, 108, 12, 203, 135, 105, - 3, 217, 196, 174, 232, 132, 8, 168, 100, 3, 25, 234, 33, 253, 65, 3, 139, - 60, 169, 234, 98, 211, 214, 213, 0}; - auto uri = NftMetadataFetcher::DecodeMetadataUri(uri_borsh_encoded); - ASSERT_TRUE(uri); - EXPECT_EQ(uri.value().spec(), - "https://" - "bafkreif4wx54wjr7pgfug3wlatr3nfntsfwngv6eusebbquezrxenj6ck4.ipfs." - "dweb.link/?ext="); - - // Iterate over each possible prefix of the uri_borsh_encoded and call - // DecodeMetadataUri on each prefix and verify that DecodeMetadataUri returns - // nullopt - size_t position_of_last_uri_byte = - /* metadata.key*/ 1 + /* metadata.update_authority */ 32 + - /* metadata.mint */ 32 + /* metadata.name length */ 4 + - /* metadata.name value */ 32 + /* metadata.symbol length */ 4 + - /* metadata.symbol value */ 10 + /* metadata.uri.length*/ 4 + - /* metadata.uri value */ 200; - ASSERT_TRUE(NftMetadataFetcher::DecodeMetadataUri( - base::span(uri_borsh_encoded).first(position_of_last_uri_byte))); - for (size_t i = position_of_last_uri_byte; i < position_of_last_uri_byte; - i++) { - ASSERT_FALSE(NftMetadataFetcher::DecodeMetadataUri( - base::span(uri_borsh_encoded).first(i))); - } - - // Invalid borsh encoding due to incorrect claimed length of metadata URI - // string (too large) fails to decode (out of bounds check) - uri_borsh_encoded = { - 4, 101, 13, 230, 18, 95, 219, 52, 174, 123, 116, 180, 35, 247, 194, 171, - 94, 148, 68, 75, 121, 55, 19, 250, 153, 7, 90, 171, 135, 29, 24, 251, 55, - 67, 195, 198, 253, 30, 138, 21, 68, 160, 113, 238, 252, 55, 9, 61, 22, - 187, 228, 119, 214, 204, 110, 244, 200, 40, 36, 82, 15, 47, 60, 157, 148, - 32, 0, 0, 0, 83, 80, 69, 67, 73, 65, 76, 32, 83, 65, 85, 67, 69, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - // next four bytes encode the URI of the string, which have been - // overridden to be incorrect (too large) - 255, 255, 255, 0, 104, 116, 116, 112, 115, 58, 47, 47, 98, 97, 102, 107, - 114, 101, 105, 102, 52, 119, 120, 53, 52, 119, 106, 114, 55, 112, 103, - 102, 117, 103, 51, 119, 108, 97, 116, 114, 51, 110, 102, 110, 116, 115, - 102, 119, 110, 103, 118, 54, 101, 117, 115, 101, 98, 98, 113, 117, 101, - 122, 114, 120, 101, 110, 106, 54, 99, 107, 52, 46, 105, 112, 102, 115, 46, - 100, 119, 101, 98, 46, 108, 105, 110, 107, 63, 101, 120, 116, 61, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 3, 0, 0, 1, 1, 255, 1, 0, 1, 1, 162, - 43, 239, 108, 12, 203, 135, 105, 3, 217, 196, 174, 232, 132, 8, 168, 100, - 3, 25, 234, 33, 253, 65, 3, 139, 60, 169, 234, 98, 211, 214, 213, 0}; - ASSERT_FALSE(NftMetadataFetcher::DecodeMetadataUri(uri_borsh_encoded)); - - // Valid borsh encoding, but invalid URI is parsed but yields empty URI - auto uri_borsh_encoded2 = base::Base64Decode( - "BGUN5hJf2zSue3S0I/fCq16UREt5NxP6mQdaq4cdGPs3Q8PG/" - "R6KFUSgce78Nwk9Frvkd9bMbvTIKCRSDy88nZQgAAAAU1BFQ0lBTCBTQVVDRQAAAAAAAAAAA" - "AAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAsAAABpbnZhbGlkIHVybOgDAQIAAABlDeYSX9s0r" - "nt0tCP3wqtelERLeTcT+pkHWquHHRj7NwFiDUmu+U8sXOOZQXL36xmknL+Zzd/" - "z3uw2G0ERMo8Eth4BAgABAf8BAAEBoivvbAzLh2kD2cSu6IQIqGQDGeoh/" - "UEDizyp6mLT1tUA"); - ASSERT_TRUE(uri_borsh_encoded2); - uri = NftMetadataFetcher::DecodeMetadataUri(*uri_borsh_encoded2); - ASSERT_TRUE(uri); - EXPECT_EQ(uri.value().spec(), ""); - - // Invalid borsh encoding is not parsed - uri_borsh_encoded2 = base::Base64Decode("d2hvb3BzIQ=="); - ASSERT_TRUE(uri_borsh_encoded2); - ASSERT_FALSE(NftMetadataFetcher::DecodeMetadataUri(*uri_borsh_encoded2)); - - ASSERT_FALSE(NftMetadataFetcher::DecodeMetadataUri({})); - - // All strings would be max size - should fail reading these strings. - ASSERT_FALSE( - NftMetadataFetcher::DecodeMetadataUri(std::vector(1000, 0xff))); - - // All strings would be zero size - should return empty url. - EXPECT_EQ(GURL(), *NftMetadataFetcher::DecodeMetadataUri( - std::vector(1000, 0x00))); -} - -} // namespace brave_wallet diff --git a/components/brave_wallet/browser/solana_keyring.cc b/components/brave_wallet/browser/solana_keyring.cc index f98621976ac..e6388f5c632 100644 --- a/components/brave_wallet/browser/solana_keyring.cc +++ b/components/brave_wallet/browser/solana_keyring.cc @@ -277,33 +277,6 @@ std::optional SolanaKeyring::GetAssociatedTokenAccount( mojom::kSolanaAssociatedTokenProgramId); } -// static -// Derive metadata account using metadata seed constant, token metadata program -// id, and the mint address as the seeds. -// https://docs.metaplex.com/programs/token-metadata/accounts#metadata -std::optional SolanaKeyring::GetAssociatedMetadataAccount( - const std::string& token_mint_address) { - std::vector> seeds; - const std::string metadata_seed_constant = "metadata"; - std::vector metaplex_seed_constant_bytes( - metadata_seed_constant.begin(), metadata_seed_constant.end()); - std::vector metadata_program_id_bytes; - std::vector token_mint_address_bytes; - - if (!Base58Decode(mojom::kSolanaMetadataProgramId, &metadata_program_id_bytes, - kSolanaPubkeySize) || - !Base58Decode(token_mint_address, &token_mint_address_bytes, - kSolanaPubkeySize)) { - return std::nullopt; - } - - seeds.push_back(std::move(metaplex_seed_constant_bytes)); - seeds.push_back(std::move(metadata_program_id_bytes)); - seeds.push_back(std::move(token_mint_address_bytes)); - - return FindProgramDerivedAddress(seeds, mojom::kSolanaMetadataProgramId); -} - std::unique_ptr SolanaKeyring::DeriveAccount( uint32_t index) const { // m/44'/501'/{index}'/0' diff --git a/components/brave_wallet/browser/solana_keyring.h b/components/brave_wallet/browser/solana_keyring.h index 7a0954504c1..037d8c45892 100644 --- a/components/brave_wallet/browser/solana_keyring.h +++ b/components/brave_wallet/browser/solana_keyring.h @@ -57,9 +57,6 @@ class SolanaKeyring { const std::string& wallet_address, mojom::SPLTokenProgram spl_token_program); - static std::optional GetAssociatedMetadataAccount( - const std::string& token_mint_address); - std::optional GetDiscoveryAddress(size_t index) const; std::vector GetHDAccountsForTesting() const; diff --git a/components/brave_wallet/browser/solana_keyring_unittest.cc b/components/brave_wallet/browser/solana_keyring_unittest.cc index 2f44e740549..288e7c32af9 100644 --- a/components/brave_wallet/browser/solana_keyring_unittest.cc +++ b/components/brave_wallet/browser/solana_keyring_unittest.cc @@ -253,19 +253,6 @@ TEST(SolanaKeyringUnitTest, GetAssociatedTokenAccount) { } } -TEST(SolanaKeyringUnitTest, GetAssociatedMetadataAccount) { - auto addr = SolanaKeyring::GetAssociatedMetadataAccount( - "5ZXToo7froykjvjnpHtTLYr9u2tW3USMwPg3sNkiaQVh"); - ASSERT_TRUE(addr); - EXPECT_EQ(*addr, "6L255rMB19d544HLNumpvbdTKkTgiQ3fgMszzX6F9VAL"); - - addr = SolanaKeyring::GetAssociatedMetadataAccount( - "8q5qbP8xu1TgDWYXokwFjgTqoSNe6W3Ljj3phwqhDKqe"); - ASSERT_TRUE(addr); - - EXPECT_EQ(*addr, "586XgHr69ZhbUkkGJsQqGt16mf7jpFS6uhnvCAwb68Qq"); -} - TEST(SolanaKeyringUnitTest, AddNewHDAccount_RestrictedAddress) { auto* registry = BlockchainRegistry::GetInstance(); CHECK(registry); diff --git a/components/brave_wallet/common/brave_wallet.mojom b/components/brave_wallet/common/brave_wallet.mojom index d68a439f9e4..ce5a8402f40 100644 --- a/components/brave_wallet/common/brave_wallet.mojom +++ b/components/brave_wallet/common/brave_wallet.mojom @@ -1861,20 +1861,6 @@ interface JsonRpcService { string chain_id) => (string allowance, ProviderError error, string error_message); - // Obtains the metadata JSON for a token ID of an ERC721 contract - GetERC721Metadata(string contract, string token_id, string chain_id) - => (string token_url, - string response, - ProviderError error, - string error_message); - - // Obtains the metadata JSON for a token ID of an ERC1155 contract - GetERC1155Metadata(string contract, string token_id, string chain_id) - => (string token_url, - string response, - ProviderError error, - string error_message); - GetUnstoppableDomainsResolveMethod() => (ResolveMethod method); GetEnsResolveMethod() => (ResolveMethod method); @@ -1992,13 +1978,6 @@ interface JsonRpcService { string wallet_address, array nft_identifiers) => (array balances, string error_message); - // Returns the metadata json associated with the NFT account address - GetSolTokenMetadata(string chain_id, string token_mint_address) - => (string token_url, - string response, - SolanaProviderError error, - string error_message); - // Returns whether a blockhash is still valid or not for a given chain. IsSolanaBlockhashValid( string chain_id, string blockhash, string? commitment) diff --git a/components/brave_wallet_ui/common/async/__mocks__/bridge.ts b/components/brave_wallet_ui/common/async/__mocks__/bridge.ts index 3f187e1befe..026ed5a6e9c 100644 --- a/components/brave_wallet_ui/common/async/__mocks__/bridge.ts +++ b/components/brave_wallet_ui/common/async/__mocks__/bridge.ts @@ -11,7 +11,6 @@ import type { AnyAction } from 'redux' // types import { BraveWallet, - CommonNftMetadata, MeldCryptoCurrency, MeldFiatCurrency, MeldFilter, @@ -1069,65 +1068,6 @@ export class MockedWalletApiProxy { errorMessage: '', } }, - // NFT Metadata - getERC721Metadata: async (contract, tokenId, chainId) => { - const mockedMetadata = mockNFTMetadata.find( - (d) => - new Amount(d.tokenID).toHex() === new Amount(tokenId).toHex() - && d.contractInformation.address === contract, - ) - if (!mockedMetadata) { - return { - error: 1, - errorMessage: 'metadata not found', - tokenUrl: '', - response: '', - } - } - return { - error: 0, - errorMessage: '', - tokenUrl: mockedMetadata.contractInformation.logo, - response: JSON.stringify({ - attributes: [ - { - trait_type: 'mocked trait name', - value: '100%', - } as { trait_type: string; value: string }, - ], - description: mockedMetadata.contractInformation.description, - image: mockedMetadata.imageURL, - name: mockedMetadata.contractInformation.name, - } as CommonNftMetadata), - } - }, - getERC1155Metadata: async (contract, tokenId, chainId) => { - return this.jsonRpcService.getERC721Metadata!(contract, tokenId, chainId) - }, - getSolTokenMetadata: async (chainId, tokenMintAddress) => { - const mockedMetadata = - mockNFTMetadata.find( - (d) => - d.tokenID === tokenMintAddress - && d.contractInformation.address === tokenMintAddress, - ) || mockNFTMetadata[0] - return { - error: 0, - errorMessage: '', - tokenUrl: mockedMetadata.contractInformation.logo, - response: JSON.stringify({ - attributes: [ - { - trait_type: 'mocked trait name', - value: '100%', - } as { trait_type: string; value: string }, - ], - description: mockedMetadata.contractInformation.description, - image: mockedMetadata.imageURL, - name: mockedMetadata.contractInformation.name, - } as CommonNftMetadata), - } - }, getNftMetadatas: async (nftIdentifiers) => { const metadatas: BraveWallet.NftMetadata[] = nftIdentifiers.map((id) => { const mockedMetadata = mockNFTMetadata.find((d) => {