diff --git a/browser/extensions/api/binance_api.cc b/browser/extensions/api/binance_api.cc index d1e4e3304421..9890d117ab19 100644 --- a/browser/extensions/api/binance_api.cc +++ b/browser/extensions/api/binance_api.cc @@ -254,6 +254,7 @@ BinanceGetDepositInfoFunction::Run() { auto* service = GetBinanceService(browser_context()); bool info_request = service->GetDepositInfo(params->symbol, + params->ticker_network, base::BindOnce( &BinanceGetDepositInfoFunction::OnGetDepositInfo, this)); @@ -267,11 +268,11 @@ BinanceGetDepositInfoFunction::Run() { void BinanceGetDepositInfoFunction::OnGetDepositInfo( const std::string& deposit_address, - const std::string& deposit_url, + const std::string& deposit_tag, bool success) { Respond(TwoArguments( std::make_unique(deposit_address), - std::make_unique(deposit_url))); + std::make_unique(deposit_tag))); } ExtensionFunction::ResponseAction @@ -362,5 +363,36 @@ void BinanceRevokeTokenFunction::OnRevokeToken(bool success) { Respond(OneArgument(std::make_unique(success))); } +ExtensionFunction::ResponseAction +BinanceGetCoinNetworksFunction::Run() { + if (!IsBinanceAPIAvailable(browser_context())) { + return RespondNow(Error("Not available in Tor/incognito/guest profile")); + } + + auto* service = GetBinanceService(browser_context()); + bool balance_success = service->GetCoinNetworks( + base::BindOnce( + &BinanceGetCoinNetworksFunction::OnGetCoinNetworks, + this)); + + if (!balance_success) { + return RespondNow(Error("Could not send request to get coin networks")); + } + + return RespondLater(); +} + +void BinanceGetCoinNetworksFunction::OnGetCoinNetworks( + const std::map& networks) { + auto coin_networks = std::make_unique( + base::Value::Type::DICTIONARY); + + for (const auto& network : networks) { + coin_networks->SetStringKey(network.first, network.second); + } + + Respond(OneArgument(std::move(coin_networks))); +} + } // namespace api } // namespace extensions diff --git a/browser/extensions/api/binance_api.h b/browser/extensions/api/binance_api.h index 9a3a02382a5d..cc5a8d63175d 100644 --- a/browser/extensions/api/binance_api.h +++ b/browser/extensions/api/binance_api.h @@ -119,7 +119,7 @@ class BinanceGetDepositInfoFunction : protected: ~BinanceGetDepositInfoFunction() override {} void OnGetDepositInfo(const std::string& deposit_address, - const std::string& deposit_url, + const std::string& deposit_tag, bool success); ResponseAction Run() override; @@ -162,6 +162,19 @@ class BinanceRevokeTokenFunction : ResponseAction Run() override; }; +class BinanceGetCoinNetworksFunction : + public ExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("binance.getCoinNetworks", UNKNOWN) + + protected: + ~BinanceGetCoinNetworksFunction() override {} + void OnGetCoinNetworks( + const std::map& networks); + + ResponseAction Run() override; +}; + } // namespace api } // namespace extensions diff --git a/browser/ui/webui/brave_webui_source.cc b/browser/ui/webui/brave_webui_source.cc index aa5c5fe54b29..b485a92e530a 100644 --- a/browser/ui/webui/brave_webui_source.cc +++ b/browser/ui/webui/brave_webui_source.cc @@ -261,6 +261,7 @@ void CustomizeWebUIHTMLSource(const std::string &name, { "binanceWidgetSearch", IDS_BINANCE_WIDGET_SEARCH }, { "binanceWidgetAddressUnavailable", IDS_BINANCE_WIDGET_ADDRESS_UNAVAILABLE }, // NOLINT { "binanceWidgetDepositAddress", IDS_BINANCE_WIDGET_DEPOSIT_ADDRESS }, + { "binanceWidgetDepositMemo", IDS_BINANCE_WIDGET_DEPOSIT_MEMO }, { "binanceWidgetConfirmConversion", IDS_BINANCE_WIDGET_CONFIRM_CONVERSION }, // NOLINT { "binanceWidgetConvert", IDS_BINANCE_WIDGET_CONVERT }, { "binanceWidgetRate", IDS_BINANCE_WIDGET_RATE }, diff --git a/common/extensions/api/binance.json b/common/extensions/api/binance.json index fb37d127c47f..7d3e29bf3f9c 100644 --- a/common/extensions/api/binance.json +++ b/common/extensions/api/binance.json @@ -198,6 +198,10 @@ { "type": "string", "name": "symbol" + }, + { + "type": "string", + "name": "tickerNetwork" }, { "type": "function", "name": "callback", @@ -207,7 +211,7 @@ "type": "string" }, { - "name": "depositURL", + "name": "depositTag", "type": "string" } ] @@ -272,6 +276,24 @@ ] } ] + }, + { + "name": "getCoinNetworks", + "type": "function", + "description": "Retrieves the primary networks for Binance assets", + "parameters": [ + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "networks", + "type": "object", + "additionalProperties": { "type": "string" } + } + ] + } + ] } ], "types": [ diff --git a/components/binance/browser/binance_json_parser.cc b/components/binance/browser/binance_json_parser.cc index c232d95e083e..a6b71f078afb 100644 --- a/components/binance/browser/binance_json_parser.cc +++ b/components/binance/browser/binance_json_parser.cc @@ -217,9 +217,9 @@ bool BinanceJSONParser::GetTickerVolumeFromJSON( // "success": true // } bool BinanceJSONParser::GetDepositInfoFromJSON( - const std::string& json, std::string *address, std::string *url) { + const std::string& json, std::string *address, std::string *tag) { DCHECK(address); - DCHECK(url); + DCHECK(tag); base::JSONReader::ValueWithError value_with_error = base::JSONReader::ReadAndReturnValueWithError( @@ -241,16 +241,11 @@ bool BinanceJSONParser::GetDepositInfoFromJSON( return false; } - std::string deposit_url; - std::string deposit_address; - - if (!data_dict->GetString("url", &deposit_url) || - !data_dict->GetString("address", &deposit_address)) { + if (!data_dict->GetString("tag", tag) || + !data_dict->GetString("address", address)) { return false; } - *url = deposit_url; - *address = deposit_address; return true; } @@ -419,3 +414,73 @@ bool BinanceJSONParser::RevokeTokenFromJSON( return true; } + +// static +// Response Format: +// { +// "code": "000000", +// "message": null, +// "messageDetail": null, +// "success": true, +// "data": [ +// { +// "coin": "CTR", +// "networkList": [ +// { +// "coin": "CTR", +// "network": "ETH" +// } +// ] +// } +// ] +// } +// +bool BinanceJSONParser::GetCoinNetworksFromJSON( + const std::string& json, std::map* networks) { + if (!networks) { + return false; + } + + base::JSONReader::ValueWithError value_with_error = + base::JSONReader::ReadAndReturnValueWithError( + json, base::JSONParserOptions::JSON_PARSE_RFC); + base::Optional& records_v = value_with_error.value; + + if (!records_v) { + LOG(ERROR) << "Invalid response, could not parse JSON, JSON is: " << json; + return false; + } + + const base::Value* data_arr = records_v->FindKey("data"); + if (!data_arr || !data_arr->is_list()) { + return false; + } + + for (const base::Value &coin : data_arr->GetList()) { + const base::Value* coin_name = coin.FindKey("coin"); + if (!coin_name || !coin_name->is_string()) { + return false; + } + + const base::Value* network_list = coin.FindKey("networkList"); + if (!network_list || !network_list->is_list()) { + return false; + } + + for (const base::Value &network : network_list->GetList()) { + const base::Value* network_name = network.FindKey("network"); + const base::Value* is_default = network.FindKey("isDefault"); + const bool default_valid = + is_default && is_default->is_bool() && is_default->GetBool(); + const bool network_name_valid = + network_name && network_name->is_string(); + + if (default_valid && network_name_valid) { + networks->insert({coin_name->GetString(), network_name->GetString()}); + break; + } + } + } + + return true; +} diff --git a/components/binance/browser/binance_json_parser.h b/components/binance/browser/binance_json_parser.h index e7e7e8686c35..0bdf38bb4bb7 100644 --- a/components/binance/browser/binance_json_parser.h +++ b/components/binance/browser/binance_json_parser.h @@ -24,7 +24,7 @@ class BinanceJSONParser { std::string* symbol_pair_volume); static bool GetDepositInfoFromJSON(const std::string& json, std::string* address, - std::string *url); + std::string* tag); static bool GetQuoteInfoFromJSON(const std::string& json, std::string* quote_id, std::string* quote_price, @@ -34,9 +34,11 @@ class BinanceJSONParser { std::string *error_message, bool* success_status); static bool GetConvertAssetsFromJSON(const std::string& json, - std::map>* assets); + std::map>* assets); static bool RevokeTokenFromJSON(const std::string& json, bool* success_status); + static bool GetCoinNetworksFromJSON(const std::string& json, + std::map* networks); }; #endif // BRAVE_COMPONENTS_BINANCE_BROWSER_BINANCE_JSON_PARSER_H_ diff --git a/components/binance/browser/binance_json_parser_unittest.cc b/components/binance/browser/binance_json_parser_unittest.cc index 9a688ccf1ad6..747e0f64d30d 100644 --- a/components/binance/browser/binance_json_parser_unittest.cc +++ b/components/binance/browser/binance_json_parser_unittest.cc @@ -12,16 +12,16 @@ namespace { -std::string GetBalanceFromAssets( - const std::map& balances, - const std::string& asset) { - std::string balance; +std::string GetValueFromStringMap( + const std::map& map, + const std::string& key) { + std::string value; std::map::const_iterator it = - balances.find(asset); - if (it != balances.end()) { - balance = it->second; + map.find(key); + if (it != map.end()) { + value = it->second; } - return balance; + return value; } typedef testing::Test BinanceJSONParserTest; @@ -50,8 +50,8 @@ TEST_F(BinanceJSONParserTest, GetAccountBalancesFromJSON) { ] })", &balances)); - std::string bnb_balance = GetBalanceFromAssets(balances, "BNB"); - std::string btc_balance = GetBalanceFromAssets(balances, "BTC"); + std::string bnb_balance = GetValueFromStringMap(balances, "BNB"); + std::string btc_balance = GetValueFromStringMap(balances, "BTC"); ASSERT_EQ(bnb_balance, "10114.00000000"); ASSERT_EQ(btc_balance, "2.45000000"); } @@ -105,20 +105,40 @@ TEST_F(BinanceJSONParserTest, GetTickerVolumeFromJSON) { TEST_F(BinanceJSONParserTest, GetDepositInfoFromJSON) { std::string deposit_address; - std::string deposit_url; + std::string deposit_tag; ASSERT_TRUE(BinanceJSONParser::GetDepositInfoFromJSON(R"( { "code": "0000", "message": "null", "data": { "coin": "BTC", + "tag": "", "address": "112tfsHDk6Yk8PbNnTVkv7yPox4aWYYDtW", "url": "https://btc.com/112tfsHDk6Yk8PbNnTVkv7yPox4aWYYDtW", "time": 1566366289000 } - })", &deposit_address, &deposit_url)); + })", &deposit_address, &deposit_tag)); ASSERT_EQ(deposit_address, "112tfsHDk6Yk8PbNnTVkv7yPox4aWYYDtW"); - ASSERT_EQ(deposit_url, "https://btc.com/112tfsHDk6Yk8PbNnTVkv7yPox4aWYYDtW"); + ASSERT_EQ(deposit_tag, ""); +} + +TEST_F(BinanceJSONParserTest, GetDepositInfoFromJSONWithTag) { + std::string deposit_address; + std::string deposit_tag; + ASSERT_TRUE(BinanceJSONParser::GetDepositInfoFromJSON(R"( + { + "code": "0000", + "message": "null", + "data": { + "coin": "EOS", + "tag": "0902394082", + "address": "binancecleos", + "url": "", + "time": 1566366289000 + } + })", &deposit_address, &deposit_tag)); + ASSERT_EQ(deposit_address, "binancecleos"); + ASSERT_EQ(deposit_tag, "0902394082"); } TEST_F(BinanceJSONParserTest, GetQuoteInfoFromJSON) { @@ -211,4 +231,50 @@ TEST_F(BinanceJSONParserTest, RevokeTokenFromJSONFail) { ASSERT_FALSE(success); } +TEST_F(BinanceJSONParserTest, GetCoinNetworksFromJSON) { + std::map networks; + ASSERT_TRUE(BinanceJSONParser::GetCoinNetworksFromJSON(R"( + { + "code": "000000", + "message": null, + "data": [ + { + "coin": "BAT", + "networkList": [ + { + "coin": "BAT", + "network": "ETH", + "isDefault": true + }, + { + "coin": "BAT", + "network": "BNB", + "isDefault": false + } + ] + }, + { + "coin": "GAS", + "networkList": [ + { + "coin": "GAS", + "network": "BTC", + "isDefault": false + }, + { + "coin": "GAS", + "network": "NEO", + "isDefault": true + } + ] + } + ] + })", &networks)); + + std::string bat_network = GetValueFromStringMap(networks, "BAT"); + std::string gas_network = GetValueFromStringMap(networks, "GAS"); + ASSERT_EQ(bat_network, "ETH"); + ASSERT_EQ(gas_network, "NEO"); +} + } // namespace diff --git a/components/binance/browser/binance_service.cc b/components/binance/browser/binance_service.cc index 830c3b8d2d0a..d12146c14132 100644 --- a/components/binance/browser/binance_service.cc +++ b/components/binance/browser/binance_service.cc @@ -39,6 +39,7 @@ namespace { const char oauth_host[] = "accounts.binance.com"; const char api_host[] = "api.binance.com"; +const char gateway_host[] = "www.binance.com"; const char oauth_callback[] = "com.brave.binance://authorization"; const char oauth_scope[] = "user:email,user:address,asset:balance,asset:ocbs"; @@ -87,6 +88,7 @@ BinanceService::BinanceService(content::BrowserContext* context) : client_id_(BINANCE_CLIENT_ID), oauth_host_(oauth_host), api_host_(api_host), + gateway_host_(gateway_host), context_(context), url_loader_factory_( content::BrowserContext::GetDefaultStoragePartition(context_) @@ -396,12 +398,32 @@ void BinanceService::OnGetTickerVolume( std::move(callback).Run(symbol_pair_volume); } +bool BinanceService::GetCoinNetworks(GetCoinNetworksCallback callback) { + auto internal_callback = base::BindOnce(&BinanceService::OnGetCoinNetworks, + base::Unretained(this), std::move(callback)); + GURL url = GetURLWithPath(gateway_host_, gateway_path_networks); + return OAuthRequest(url, "GET", "", std::move(internal_callback)); +} + +void BinanceService::OnGetCoinNetworks( + GetCoinNetworksCallback callback, + const int status, const std::string& body, + const std::map& headers) { + std::map networks; + if (status >= 200 && status <= 299) { + BinanceJSONParser::GetCoinNetworksFromJSON(body, &networks); + } + std::move(callback).Run(networks); +} + bool BinanceService::GetDepositInfo(const std::string& symbol, + const std::string& ticker_network, GetDepositInfoCallback callback) { auto internal_callback = base::BindOnce(&BinanceService::OnGetDepositInfo, base::Unretained(this), std::move(callback)); GURL url = GetURLWithPath(oauth_host_, oauth_path_deposit_info); url = net::AppendQueryParameter(url, "coin", symbol); + url = net::AppendQueryParameter(url, "network", ticker_network); url = net::AppendQueryParameter(url, "access_token", access_token_); return OAuthRequest(url, "GET", "", std::move(internal_callback)); } @@ -411,15 +433,15 @@ void BinanceService::OnGetDepositInfo( const int status, const std::string& body, const std::map& headers) { std::string deposit_address; - std::string deposit_url; + std::string deposit_tag; bool success = status >= 200 && status <= 299; if (success) { BinanceJSONParser::GetDepositInfoFromJSON( - body, &deposit_address, &deposit_url); + body, &deposit_address, &deposit_tag); } std::move(callback).Run( - deposit_address, deposit_url, success); + deposit_address, deposit_tag, success); } bool BinanceService::ConfirmConvert(const std::string& quote_id, @@ -510,3 +532,7 @@ void BinanceService::SetOAuthHostForTest(const std::string& oauth_host) { void BinanceService::SetAPIHostForTest(const std::string& api_host) { api_host_ = api_host; } + +void BinanceService::SetGatewayHostForTest(const std::string& gateway_host) { + gateway_host_ = gateway_host; +} diff --git a/components/binance/browser/binance_service.h b/components/binance/browser/binance_service.h index 4fc77f5be50f..26e1f35a1dc2 100644 --- a/components/binance/browser/binance_service.h +++ b/components/binance/browser/binance_service.h @@ -49,6 +49,9 @@ const char oauth_path_revoke_token[] = "/oauth-api/v1/revoke-token"; const char api_path_ticker_price[] = "/api/v3/ticker/price"; const char api_path_ticker_volume[] = "/api/v3/ticker/24hr"; +const char gateway_path_networks[] = + "/gateway-api/v1/public/capital/getNetworkCoinAll"; + class BinanceService : public KeyedService { public: explicit BinanceService(content::BrowserContext* context); @@ -71,6 +74,8 @@ class BinanceService : public KeyedService { using GetTickerPriceCallback = base::OnceCallback; using GetTickerVolumeCallback = base::OnceCallback; using RevokeTokenCallback = base::OnceCallback; + using GetCoinNetworksCallback = base::OnceCallback< + void(const std::map&)>; bool GetAccessToken(GetAccessTokenCallback callback); bool GetConvertQuote(const std::string& from, @@ -79,6 +84,7 @@ class BinanceService : public KeyedService { GetConvertQuoteCallback callback); bool GetAccountBalances(GetAccountBalancesCallback callback); bool GetDepositInfo(const std::string& symbol, + const std::string& ticker_network, GetDepositInfoCallback callback); bool ConfirmConvert(const std::string& quote_id, ConfirmConvertCallback callback); @@ -88,6 +94,7 @@ class BinanceService : public KeyedService { bool GetTickerVolume(const std::string& symbol_pair, GetTickerVolumeCallback callback); bool RevokeToken(RevokeTokenCallback callback); + bool GetCoinNetworks(GetCoinNetworksCallback callback); std::string GetBinanceTLD(); std::string GetOAuthClientUrl(); @@ -134,6 +141,9 @@ class BinanceService : public KeyedService { void OnRevokeToken(RevokeTokenCallback callback, const int status, const std::string& body, const std::map& headers); + void OnGetCoinNetworks(GetCoinNetworksCallback callback, + const int status, const std::string& body, + const std::map& headers); bool OAuthRequest(const GURL& url, const std::string& method, const std::string& post_data, URLRequestCallback callback); bool LoadTokensFromPrefs(); @@ -144,6 +154,7 @@ class BinanceService : public KeyedService { void SetClientIdForTest(const std::string& client_id); void SetOAuthHostForTest(const std::string& oauth_host); void SetAPIHostForTest(const std::string& api_host); + void SetGatewayHostForTest(const std::string& gateway_host); scoped_refptr io_task_runner_; std::string auth_token_; @@ -154,6 +165,7 @@ class BinanceService : public KeyedService { std::string client_id_; std::string oauth_host_; std::string api_host_; + std::string gateway_host_; content::BrowserContext* context_; scoped_refptr url_loader_factory_; diff --git a/components/binance/browser/binance_service_browsertest.cc b/components/binance/browser/binance_service_browsertest.cc index 10efdff6a2d9..332fa3b752d9 100644 --- a/components/binance/browser/binance_service_browsertest.cc +++ b/components/binance/browser/binance_service_browsertest.cc @@ -148,6 +148,43 @@ std::unique_ptr HandleRequest( "data": true, "success": true })"); + } else if (request_path == gateway_path_networks) { + http_response->set_content(R"({ + "code": "000000", + "message": null, + "data": [ + { + "coin": "BAT", + "networkList": [ + { + "coin": "BAT", + "network": "ETH", + "isDefault": true + }, + { + "coin": "BAT", + "network": "BNB", + "isDefault": false + } + ] + }, + { + "coin": "GAS", + "networkList": [ + { + "coin": "GAS", + "network": "BTC", + "isDefault": false + }, + { + "coin": "GAS", + "network": "NEO", + "isDefault": true + } + ] + } + ] + })"); } return std::move(http_response); } @@ -211,6 +248,7 @@ class BinanceAPIBrowserTest : public InProcessBrowserTest { std::to_string(https_server_->port()); service->SetAPIHostForTest(host); service->SetOAuthHostForTest(host); + service->SetGatewayHostForTest(host); } void OnGetAccessToken(bool unauthorized, bool check_set_prefs) { @@ -285,24 +323,24 @@ class BinanceAPIBrowserTest : public InProcessBrowserTest { wait_for_request_->Run(); } - void OnGetDepositInfo(const std::string& address, const std::string& url, + void OnGetDepositInfo(const std::string& address, const std::string& tag, bool success) { if (wait_for_request_) { wait_for_request_->Quit(); } ASSERT_EQ(expected_address_, address); - ASSERT_EQ(expected_url_, url); + ASSERT_EQ(expected_tag_, tag); ASSERT_EQ(expected_success_, success); } void WaitForGetDepositInfo( - const std::string& expected_address, const std::string& expected_url, + const std::string& expected_address, const std::string& expected_tag, bool expected_success) { if (wait_for_request_) { return; } expected_address_ = expected_address; - expected_url_ = expected_url; + expected_tag_ = expected_tag; expected_success_ = expected_success; wait_for_request_.reset(new base::RunLoop); wait_for_request_->Run(); @@ -399,6 +437,23 @@ class BinanceAPIBrowserTest : public InProcessBrowserTest { wait_for_request_->Run(); } + void OnGetCoinNetworks(const std::map& networks) { + if (wait_for_request_) { + wait_for_request_->Quit(); + } + ASSERT_EQ(expected_networks_, networks); + } + + void WaitForGetCoinNetworks( + const std::map& expected_networks) { + if (wait_for_request_) { + return; + } + expected_networks_ = expected_networks; + wait_for_request_.reset(new base::RunLoop); + wait_for_request_->Run(); + } + content::WebContents* active_contents() { return browser()->tab_strip_model()->GetActiveWebContents(); } @@ -429,12 +484,13 @@ class BinanceAPIBrowserTest : public InProcessBrowserTest { std::string expected_total_fee_; std::string expected_total_amount_; std::string expected_address_; - std::string expected_url_; + std::string expected_tag_; std::string expected_error_message_; std::string expected_symbol_pair_price_; std::string expected_symbol_pair_volume_; std::vector expected_assets_; std::map expected_balances_; + std::map expected_networks_; std::map> expected_assets_with_sub_; std::unique_ptr wait_for_request_; @@ -584,20 +640,20 @@ IN_PROC_BROWSER_TEST_F(BinanceAPIBrowserTest, GetDepositInfo) { ResetHTTPSServer(base::BindRepeating(&HandleRequest)); EXPECT_TRUE(NavigateToNewTabUntilLoadStop()); auto* service = GetBinanceService(); - ASSERT_TRUE(service->GetDepositInfo("BTC", + ASSERT_TRUE(service->GetDepositInfo("BTC", "BTC", base::BindOnce( &BinanceAPIBrowserTest::OnGetDepositInfo, base::Unretained(this)))); std::string address = "112tfsHDk6Yk8PbNnTVkv7yPox4aWYYDtW"; - std::string url = "https://btc.com/112tfsHDk6Yk8PbNnTVkv7yPox4aWYYDtW"; - WaitForGetDepositInfo(address, url, true); + std::string tag = ""; + WaitForGetDepositInfo(address, tag, true); } IN_PROC_BROWSER_TEST_F(BinanceAPIBrowserTest, GetDepositInfoUnauthorized) { ResetHTTPSServer(base::BindRepeating(&HandleRequestUnauthorized)); EXPECT_TRUE(NavigateToNewTabUntilLoadStop()); auto* service = GetBinanceService(); - ASSERT_TRUE(service->GetDepositInfo("BTC", + ASSERT_TRUE(service->GetDepositInfo("BTC", "BTC", base::BindOnce( &BinanceAPIBrowserTest::OnGetDepositInfo, base::Unretained(this)))); @@ -608,7 +664,7 @@ IN_PROC_BROWSER_TEST_F(BinanceAPIBrowserTest, GetDepositInfoServerError) { ResetHTTPSServer(base::BindRepeating(&HandleRequestServerError)); EXPECT_TRUE(NavigateToNewTabUntilLoadStop()); auto* service = GetBinanceService(); - ASSERT_TRUE(service->GetDepositInfo("BTC", + ASSERT_TRUE(service->GetDepositInfo("BTC", "BTC", base::BindOnce( &BinanceAPIBrowserTest::OnGetDepositInfo, base::Unretained(this)))); @@ -826,3 +882,42 @@ IN_PROC_BROWSER_TEST_F(BinanceAPIBrowserTest, &result)); ASSERT_FALSE(result); } + +IN_PROC_BROWSER_TEST_F(BinanceAPIBrowserTest, GetCoinNetworks) { + ResetHTTPSServer(base::BindRepeating(&HandleRequest)); + EXPECT_TRUE(NavigateToNewTabUntilLoadStop()); + auto* service = GetBinanceService(); + ASSERT_TRUE(service->GetCoinNetworks( + base::BindOnce( + &BinanceAPIBrowserTest::OnGetCoinNetworks, + base::Unretained(this)))); + WaitForGetCoinNetworks( + std::map { + {"BAT", "ETH"}, + {"GAS", "NEO"} + }); +} + +IN_PROC_BROWSER_TEST_F(BinanceAPIBrowserTest, GetCoinNetworksUnauthorized) { + ResetHTTPSServer(base::BindRepeating(&HandleRequestUnauthorized)); + EXPECT_TRUE(NavigateToNewTabUntilLoadStop()); + auto* service = GetBinanceService(); + ASSERT_TRUE(service->GetCoinNetworks( + base::BindOnce( + &BinanceAPIBrowserTest::OnGetCoinNetworks, + base::Unretained(this)))); + WaitForGetCoinNetworks( + std::map()); +} + +IN_PROC_BROWSER_TEST_F(BinanceAPIBrowserTest, GetCoinNetworksServerError) { + ResetHTTPSServer(base::BindRepeating(&HandleRequestServerError)); + EXPECT_TRUE(NavigateToNewTabUntilLoadStop()); + auto* service = GetBinanceService(); + ASSERT_TRUE(service->GetCoinNetworks( + base::BindOnce( + &BinanceAPIBrowserTest::OnGetCoinNetworks, + base::Unretained(this)))); + WaitForGetCoinNetworks( + std::map()); +} diff --git a/components/brave_new_tab_ui/actions/new_tab_actions.ts b/components/brave_new_tab_ui/actions/new_tab_actions.ts index 6e5050921bc4..b4f601dd7221 100644 --- a/components/brave_new_tab_ui/actions/new_tab_actions.ts +++ b/components/brave_new_tab_ui/actions/new_tab_actions.ts @@ -153,10 +153,10 @@ export const onAssetUSDPrice = (ticker: string, price: string) => action(types.O price }) -export const onAssetDepositInfo = (symbol: string, address: string, url: string) => action(types.ON_ASSET_DEPOSIT_INFO, { +export const onAssetDepositInfo = (symbol: string, address: string, tag: string) => action(types.ON_ASSET_DEPOSIT_INFO, { symbol, address, - url + tag }) export const onDepositQRForAsset = (asset: string, imageSrc: string) => action(types.ON_DEPOSIT_QR_FOR_ASSET, { diff --git a/components/brave_new_tab_ui/components/default/binance/index.tsx b/components/brave_new_tab_ui/components/default/binance/index.tsx index 4724a202ebdd..ee59b736ec4f 100644 --- a/components/brave_new_tab_ui/components/default/binance/index.tsx +++ b/components/brave_new_tab_ui/components/default/binance/index.tsx @@ -154,12 +154,11 @@ interface Props { onUpdateActions: () => void onDismissAuthInvalid: () => void onSetSelectedView: (view: string) => void + getCurrencyList: () => string[] } class Binance extends React.PureComponent { private fiatList: string[] - private usCurrencies: string[] - private comCurrencies: string[] private currencyNames: Record private cryptoColors: Record private convertTimer: any @@ -195,8 +194,6 @@ class Binance extends React.PureComponent { } this.cryptoColors = currencyData.cryptoColors this.fiatList = currencyData.fiatList - this.usCurrencies = currencyData.usCurrencies - this.comCurrencies = currencyData.comCurrencies this.currencyNames = { 'BAT': 'Basic Attent...', 'BTC': 'Bitcoin', @@ -584,22 +581,6 @@ class Binance extends React.PureComponent { } } - getCurrencyList = () => { - const { accountBalances, userTLD } = this.props - const baseList = userTLD === 'us' ? this.usCurrencies : this.comCurrencies - - if (!accountBalances) { - return baseList - } - - const accounts = Object.keys(accountBalances) - const nonHoldingList = baseList.filter((symbol: string) => { - return !accounts.includes(symbol) - }) - - return accounts.concat(nonHoldingList) - } - renderIconAsset = (key: string, isDetail: boolean = false) => { const iconColor = this.cryptoColors[key] || '#fff' @@ -759,8 +740,11 @@ class Binance extends React.PureComponent { const { assetDepositInfo } = this.props const addressInfo = assetDepositInfo[currentDepositAsset] const address = addressInfo && addressInfo.address + const tag = addressInfo && addressInfo.tag const cleanName = this.currencyNames[currentDepositAsset] const cleanNameDisplay = cleanName ? `(${cleanName})` : '' + const depositData = tag || address + const label = tag ? 'binanceWidgetDepositMemo' : 'binanceWidgetDepositAddress' return ( <> @@ -780,7 +764,7 @@ class Binance extends React.PureComponent { {cleanNameDisplay} { - address + depositData ? @@ -791,19 +775,19 @@ class Binance extends React.PureComponent { - {`${currentDepositAsset} ${getLocale('binanceWidgetDepositAddress')}`} + {`${currentDepositAsset} ${getLocale(label)}`} { - address - ? address + depositData + ? depositData : getLocale('binanceWidgetAddressUnavailable') } { - address - ? + depositData + ? {getLocale('binanceWidgetCopy')} : null @@ -817,7 +801,7 @@ class Binance extends React.PureComponent { renderDepositView = () => { const { currencyNames } = this const { currentDepositSearch, currentDepositAsset } = this.state - const currencyList = this.getCurrencyList() + const currencyList = this.props.getCurrencyList() if (currentDepositAsset) { return this.renderCurrentDepositAsset() @@ -872,9 +856,10 @@ class Binance extends React.PureComponent { hideBalance, accountBTCValue, accountBTCUSDValue, - assetUSDValues + assetUSDValues, + getCurrencyList } = this.props - const currencyList = this.getCurrencyList() + const currencyList = getCurrencyList() const totalBTCUSDValue = accountBTCUSDValue || '0.00' const totalBTCValue = accountBTCValue ? this.formatCryptoBalance(accountBTCValue) : '0.000000' @@ -1163,15 +1148,16 @@ class Binance extends React.PureComponent { initialAsset, initialFiat, initialAmount, - userAuthed + userAuthed, + getCurrencyList } = this.props const { fiatShowing, currenciesShowing } = this.state const isUS = userTLD === 'us' - const currencies = this.getCurrencyList() const ButtonComponent = userAuthed ? ActionButton : ConnectButton + const currencies = getCurrencyList() return ( <> diff --git a/components/brave_new_tab_ui/components/default/binance/style.ts b/components/brave_new_tab_ui/components/default/binance/style.ts index 202615d6c8a1..d0d5beeca6f9 100644 --- a/components/brave_new_tab_ui/components/default/binance/style.ts +++ b/components/brave_new_tab_ui/components/default/binance/style.ts @@ -365,7 +365,7 @@ export const MemoArea = styled<{}, 'div'>('div')` export const MemoInfo = styled<{}, 'div'>('div')` float: left; - max-width: 110px; + max-width: 160px; ` export const CopyButton = styled(GenButton)` diff --git a/components/brave_new_tab_ui/containers/newTab/index.tsx b/components/brave_new_tab_ui/containers/newTab/index.tsx index 9e3cabb3fd3d..de984bc9d21f 100644 --- a/components/brave_new_tab_ui/containers/newTab/index.tsx +++ b/components/brave_new_tab_ui/containers/newTab/index.tsx @@ -29,6 +29,7 @@ import { SortEnd } from 'react-sortable-hoc' import * as newTabActions from '../../actions/new_tab_actions' import * as gridSitesActions from '../../actions/grid_sites_actions' import { getLocale } from '../../../common/locale' +import currencyData from '../../components/default/binance/data' interface Props { newTabData: NewTab.State @@ -395,6 +396,23 @@ class NewTabPage extends React.Component { this.getConvertAssets() } + getCurrencyList = () => { + const { accountBalances, userTLD } = this.props.newTabData.binanceState + const { usCurrencies, comCurrencies } = currencyData + const baseList = userTLD === 'us' ? usCurrencies : comCurrencies + + if (!accountBalances) { + return baseList + } + + const accounts = Object.keys(accountBalances) + const nonHoldingList = baseList.filter((symbol: string) => { + return !accounts.includes(symbol) + }) + + return accounts.concat(nonHoldingList) + } + getConvertAssets = () => { chrome.binance.getConvertAssets((assets: any) => { for (let asset in assets) { @@ -434,12 +452,20 @@ class NewTabPage extends React.Component { this.setAssetUSDPrice(ticker, price) }) } - chrome.binance.getDepositInfo(ticker, (address: string, url: string) => { - this.setAssetDepositInfo(ticker, address, url) - generateQRData(address, ticker, this.setAssetDepositQRCodeSrc) - }) } + chrome.binance.getCoinNetworks((networks: Record) => { + const currencies = this.getCurrencyList() + for (let ticker in networks) { + if (currencies.includes(ticker)) { + chrome.binance.getDepositInfo(ticker, networks[ticker], (address: string, tag: string) => { + this.setAssetDepositInfo(ticker, address, tag) + generateQRData((tag || address), ticker, this.setAssetDepositQRCodeSrc) + }) + } + } + }) + setTimeout(() => { this.setBinanceBalances(balances) }, 1500) @@ -574,6 +600,7 @@ class NewTabPage extends React.Component { onUpdateActions={this.updateActions} onDismissAuthInvalid={this.dismissAuthInvalid} onSetSelectedView={this.setSelectedView} + getCurrencyList={this.getCurrencyList} /> ) } diff --git a/components/brave_new_tab_ui/reducers/new_tab_reducer.ts b/components/brave_new_tab_ui/reducers/new_tab_reducer.ts index 2ccb157e1275..98e47cf0d996 100644 --- a/components/brave_new_tab_ui/reducers/new_tab_reducer.ts +++ b/components/brave_new_tab_ui/reducers/new_tab_reducer.ts @@ -537,8 +537,8 @@ export const newTabReducer: Reducer = (state: NewTab.S break case types.ON_ASSET_DEPOSIT_INFO: - const { symbol, address, url } = payload - if (!symbol || !address || !url) { + const { symbol, address, tag } = payload + if (!symbol || (!address && !tag)) { break } @@ -548,7 +548,7 @@ export const newTabReducer: Reducer = (state: NewTab.S } state.binanceState.assetDepositInfo[symbol] = { address, - url + tag } break diff --git a/components/definitions/chromel.d.ts b/components/definitions/chromel.d.ts index be39e66b7ce1..9fc2d41f9435 100644 --- a/components/definitions/chromel.d.ts +++ b/components/definitions/chromel.d.ts @@ -161,7 +161,8 @@ declare namespace chrome.binance { const getConvertQuote: (from: string, to: string, amount: string, callback: (quote: any) => void) => {} const getTickerPrice: (symbolPair: string, callback: (symbolPairValue: string) => void) => {} const getTickerVolume: (symbolPair: string, callback: (symbolPairVolume: string) => void) => {} - const getDepositInfo: (symbol: string, callback: (depositAddress: string, depositURL: string) => void) => {} + const getDepositInfo: (symbol: string, tickerNetwork: string, callback: (depositAddress: string, depositTag: string) => void) => {} + const getCoinNetworks: (callback: (networks: Record) => void) => {} const getConvertAssets: (callback: (supportedAssets: any) => void) => {} const confirmConvert: (quoteId: string, callback: (success: boolean, message: string) => void) => {} const revokeToken: (callback: (success: boolean) => void) => {} diff --git a/components/resources/brave_components_strings.grd b/components/resources/brave_components_strings.grd index 4dbce17efe4a..b390921a2e47 100644 --- a/components/resources/brave_components_strings.grd +++ b/components/resources/brave_components_strings.grd @@ -773,8 +773,9 @@ Retry Done Copy - Address Not Available + Info Not Available Deposit Address + Deposit Memo Search Confirm Conversion