Skip to content

Commit

Permalink
Fixes brave/brave-browser#9250 - Showing all deposit addresses in Bin…
Browse files Browse the repository at this point in the history
…ance widget
  • Loading branch information
ryanml committed Apr 29, 2020
1 parent ae82991 commit be3049e
Show file tree
Hide file tree
Showing 12 changed files with 373 additions and 44 deletions.
32 changes: 32 additions & 0 deletions browser/extensions/api/binance_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down Expand Up @@ -362,5 +363,36 @@ void BinanceRevokeTokenFunction::OnRevokeToken(bool success) {
Respond(OneArgument(std::make_unique<base::Value>(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<std::string, std::string>& networks) {
auto coin_networks = std::make_unique<base::Value>(
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
13 changes: 13 additions & 0 deletions browser/extensions/api/binance_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string, std::string>& networks);

ResponseAction Run() override;
};

} // namespace api
} // namespace extensions

Expand Down
22 changes: 22 additions & 0 deletions common/extensions/api/binance.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@
{
"type": "string",
"name": "symbol"
},
{
"type": "string",
"name": "tickerNetwork"
}, {
"type": "function",
"name": "callback",
Expand Down Expand Up @@ -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": [
Expand Down
70 changes: 70 additions & 0 deletions components/binance/browser/binance_json_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,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<std::string, std::string>* networks) {
if (!networks) {
return false;
}

base::JSONReader::ValueWithError value_with_error =
base::JSONReader::ReadAndReturnValueWithError(
json, base::JSONParserOptions::JSON_PARSE_RFC);
base::Optional<base::Value>& 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;
}
4 changes: 3 additions & 1 deletion components/binance/browser/binance_json_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ class BinanceJSONParser {
std::string *error_message,
bool* success_status);
static bool GetConvertAssetsFromJSON(const std::string& json,
std::map<std::string, std::vector<std::string>>* assets);
std::map<std::string, std::vector<std::string>>* assets);
static bool RevokeTokenFromJSON(const std::string& json,
bool* success_status);
static bool GetCoinNetworksFromJSON(const std::string& json,
std::map<std::string, std::string>* networks);
};

#endif // BRAVE_COMPONENTS_BINANCE_BROWSER_BINANCE_JSON_PARSER_H_
66 changes: 56 additions & 10 deletions components/binance/browser/binance_json_parser_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@

namespace {

std::string GetBalanceFromAssets(
const std::map<std::string, std::string>& balances,
const std::string& asset) {
std::string balance;
std::string GetValueFromStringMap(
const std::map<std::string, std::string>& map,
const std::string& key) {
std::string value;
std::map<std::string, std::string>::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;
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -211,4 +211,50 @@ TEST_F(BinanceJSONParserTest, RevokeTokenFromJSONFail) {
ASSERT_FALSE(success);
}

TEST_F(BinanceJSONParserTest, GetCoinNetworksFromJSON) {
std::map<std::string, std::string> 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
26 changes: 26 additions & 0 deletions components/binance/browser/binance_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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_)
Expand Down Expand Up @@ -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<std::string, std::string>& headers) {
std::map<std::string, std::string> 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));
}
Expand Down Expand Up @@ -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;
}
12 changes: 12 additions & 0 deletions components/binance/browser/binance_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -71,6 +74,8 @@ class BinanceService : public KeyedService {
using GetTickerPriceCallback = base::OnceCallback<void(const std::string&)>;
using GetTickerVolumeCallback = base::OnceCallback<void(const std::string&)>;
using RevokeTokenCallback = base::OnceCallback<void(bool)>;
using GetCoinNetworksCallback = base::OnceCallback<
void(const std::map<std::string, std::string>&)>;

bool GetAccessToken(GetAccessTokenCallback callback);
bool GetConvertQuote(const std::string& from,
Expand All @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -134,6 +141,9 @@ class BinanceService : public KeyedService {
void OnRevokeToken(RevokeTokenCallback callback,
const int status, const std::string& body,
const std::map<std::string, std::string>& headers);
void OnGetCoinNetworks(GetCoinNetworksCallback callback,
const int status, const std::string& body,
const std::map<std::string, std::string>& headers);
bool OAuthRequest(const GURL& url, const std::string& method,
const std::string& post_data, URLRequestCallback callback);
bool LoadTokensFromPrefs();
Expand All @@ -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<base::SequencedTaskRunner> io_task_runner_;
std::string auth_token_;
Expand All @@ -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<network::SharedURLLoaderFactory> url_loader_factory_;
Expand Down
Loading

0 comments on commit be3049e

Please sign in to comment.