Skip to content

Commit

Permalink
Add core Stripe onramp support (#18696)
Browse files Browse the repository at this point in the history
  • Loading branch information
nvonpentz authored Jun 6, 2023
1 parent 3a4b4ae commit 3d575a8
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 1 deletion.
6 changes: 6 additions & 0 deletions components/brave_wallet/api/asset_ratio.idl
Original file line number Diff line number Diff line change
Expand Up @@ -196,5 +196,11 @@ namespace asset_ratio {
// A payload list.
CoinMarketPayload[] payload;
};

// A payload with a URL field
dictionary StripeBuyURLResponse {
// e.g "https://crypto.link.com?session_hash=abcdefgh"
DOMString url;
};

};
15 changes: 15 additions & 0 deletions components/brave_wallet/browser/asset_ratio_response_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,19 @@ absl::optional<std::vector<mojom::CoinMarketPtr>> ParseCoinMarkets(
return values;
}

absl::optional<std::string> ParseStripeBuyURL(const base::Value& json_value) {
// Parses results like this:
// {
// "url": "https://crypto.link.com?session_hash=abcdefgh"
// }
auto stripe_buy_url_response =
api::asset_ratio::StripeBuyURLResponse::FromValue(json_value);

if (!stripe_buy_url_response) {
return absl::nullopt;
}

return stripe_buy_url_response->url;
}

} // namespace brave_wallet
2 changes: 2 additions & 0 deletions components/brave_wallet/browser/asset_ratio_response_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ bool ParseAssetPriceHistory(const base::Value& json_value,
absl::optional<std::vector<mojom::CoinMarketPtr>> ParseCoinMarkets(
const base::Value& json_value);

absl::optional<std::string> ParseStripeBuyURL(const base::Value& json_value);

mojom::BlockchainTokenPtr ParseTokenInfo(const base::Value& json_value,
const std::string& chain_id,
mojom::CoinType coin);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,22 @@ TEST(AssetRatioResponseParserUnitTest, ParseCoinMarkets) {
EXPECT_FALSE(ParseCoinMarkets(ParseJson(json)));
}

TEST(AssetRatioResponseParserUnitTest, ParseStripeBuyURL) {
std::string json(R"({
"url": "https://crypto.link.com?session_hash=abcdefgh"
})");

auto parsed_value = ParseStripeBuyURL(ParseJson(json));
ASSERT_TRUE(parsed_value);
EXPECT_EQ(*parsed_value, "https://crypto.link.com?session_hash=abcdefgh");

// Invalid input
json = R"({"url": []})";
EXPECT_FALSE(ParseStripeBuyURL(ParseJson(json)));
json = "3";
EXPECT_FALSE(ParseStripeBuyURL(ParseJson(json)));
json = "[3]";
EXPECT_FALSE(ParseStripeBuyURL(ParseJson(json)));
}

} // namespace brave_wallet
73 changes: 73 additions & 0 deletions components/brave_wallet/browser/asset_ratio_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "base/strings/stringprintf.h"
#include "brave/components/api_request_helper/api_request_helper.h"
#include "brave/components/brave_wallet/browser/brave_wallet_constants.h"
#include "brave/components/brave_wallet/browser/json_rpc_requests_helper.h"
#include "brave/components/constants/brave_services_key.h"
#include "net/base/load_flags.h"
#include "net/base/url_util.h"
Expand Down Expand Up @@ -94,6 +95,20 @@ std::vector<std::string> VectorToLowerCase(const std::vector<std::string>& v) {
return v_lower;
}

absl::optional<std::string> ChainIdToStripeChainId(
const std::string& chain_id) {
static base::NoDestructor<base::flat_map<std::string, std::string>>
chain_id_lookup(
{{brave_wallet::mojom::kMainnetChainId, "ethereum"},
{brave_wallet::mojom::kSolanaMainnet, "solana"},
{brave_wallet::mojom::kPolygonMainnetChainId, "polygon"}});
if (!chain_id_lookup->contains(chain_id)) {
return absl::nullopt;
}

return chain_id_lookup->at(chain_id);
}

} // namespace

namespace brave_wallet {
Expand Down Expand Up @@ -239,6 +254,9 @@ void AssetRatioService::GetBuyUrlV1(mojom::OnRampProvider provider,
net::AppendQueryParameter(transak_url, "apiKey", kTransakApiKey);

std::move(callback).Run(std::move(transak_url.spec()), absl::nullopt);
} else if (provider == mojom::OnRampProvider::kStripe) {
GetStripeBuyURL(std::move(callback), address, currency_code, amount,
chain_id, symbol);
} else {
std::move(callback).Run(url, "UNSUPPORTED_ONRAMP_PROVIDER");
}
Expand Down Expand Up @@ -324,6 +342,61 @@ void AssetRatioService::OnGetSardineAuthToken(
std::move(callback).Run(std::move(sardine_buy_url.spec()), absl::nullopt);
}

void AssetRatioService::GetStripeBuyURL(
GetBuyUrlV1Callback callback,
const std::string& address,
const std::string& source_currency,
const std::string& source_exchange_amount,
const std::string& chain_id,
const std::string& destination_currency) {
// Convert the frontend supplied chain ID to the chain ID used by Stripe
absl::optional<std::string> destination_network =
ChainIdToStripeChainId(chain_id);
if (!destination_network) {
std::move(callback).Run("", "UNSUPPORTED_CHAIN_ID");
return;
}

base::Value::Dict payload;
AddKeyIfNotEmpty(&payload, "wallet_address", address);
AddKeyIfNotEmpty(&payload, "source_currency", source_currency);
AddKeyIfNotEmpty(&payload, "source_exchange_amount", source_exchange_amount);
AddKeyIfNotEmpty(&payload, "destination_network", *destination_network);
AddKeyIfNotEmpty(&payload, "destination_currency", destination_currency);

const std::string json_payload = GetJSON(payload);

GURL url = GURL(base::StringPrintf("%sv2/stripe/onramp_sessions",
base_url_for_test_.is_empty()
? kAssetRatioBaseURL
: base_url_for_test_.spec().c_str()));

auto internal_callback =
base::BindOnce(&AssetRatioService::OnGetStripeBuyURL,
weak_ptr_factory_.GetWeakPtr(), std::move(callback));

api_request_helper_->Request(
"POST", url, json_payload, "application/json",
std::move(internal_callback), {},
{.auto_retry_on_network_change = true, .enable_cache = false});
}

void AssetRatioService::OnGetStripeBuyURL(GetBuyUrlV1Callback callback,
APIRequestResult api_request_result) {
if (!api_request_result.Is2XXResponseCode()) {
std::move(callback).Run("", "INTERNAL_SERVICE_ERROR");
return;
}

auto url = ParseStripeBuyURL(api_request_result.value_body());
if (!url) {
std::move(callback).Run("", "PARSING_ERROR");
return;
}

std::move(callback).Run(*url, absl::nullopt);
}

void AssetRatioService::OnGetPrice(std::vector<std::string> from_assets,
std::vector<std::string> to_assets,
GetPriceCallback callback,
Expand Down
12 changes: 12 additions & 0 deletions components/brave_wallet/browser/asset_ratio_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class AssetRatioService : public KeyedService, public mojom::AssetRatioService {
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);

private:
friend class AssetRatioServiceUnitTest;
FRIEND_TEST_ALL_PREFIXES(AssetRatioServiceUnitTest, GetStripeBuyURL);
void OnGetSardineAuthToken(const std::string& network,
const std::string& address,
const std::string& symbol,
Expand All @@ -111,6 +113,16 @@ class AssetRatioService : public KeyedService, public mojom::AssetRatioService {
GetBuyUrlV1Callback callback,
APIRequestResult api_request_result);

void GetStripeBuyURL(GetBuyUrlV1Callback callback,
const std::string& address,
const std::string& source_currency,
const std::string& source_exchange_amount,
const std::string& chain_id,
const std::string& destination_currency);

void OnGetStripeBuyURL(GetBuyUrlV1Callback callback,
APIRequestResult api_request_result);

void OnGetPrice(std::vector<std::string> from_assets,
std::vector<std::string> to_assets,
GetPriceCallback callback,
Expand Down
22 changes: 22 additions & 0 deletions components/brave_wallet/browser/asset_ratio_service_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -534,4 +534,26 @@ TEST_F(AssetRatioServiceUnitTest, GetCoinMarketsUnexpectedResponse) {
EXPECT_TRUE(callback_run);
}

TEST_F(AssetRatioServiceUnitTest, GetStripeBuyURL) {
SetInterceptor(R"({
"url": "https://crypto.link.com?session_hash=abcdefgh"
})");

TestGetBuyUrlV1(mojom::OnRampProvider::kStripe, mojom::kMainnetChainId,
"0xdeadbeef", "USDC", "55000000", "USD",
"https://crypto.link.com?session_hash=abcdefgh",
absl::nullopt);

// Test with unexpected response
SetInterceptor("mischief managed");
TestGetBuyUrlV1(mojom::OnRampProvider::kStripe, mojom::kMainnetChainId,
"0xdeadbeef", "USDC", "55000000", "USD", "", "PARSING_ERROR");

// Test with non 2XX response
SetErrorInterceptor("");
TestGetBuyUrlV1(mojom::OnRampProvider::kStripe, mojom::kMainnetChainId,
"0xdeadbeef", "USDC", "55000000", "USD", "",
"INTERNAL_SERVICE_ERROR");
}

} // namespace brave_wallet
3 changes: 2 additions & 1 deletion components/brave_wallet/common/brave_wallet.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,8 @@ interface KeyringServiceObserver {
enum OnRampProvider {
kRamp = 0,
kSardine = 1,
kTransak = 2
kTransak = 2,
kStripe = 3
};

enum OffRampProvider {
Expand Down

0 comments on commit 3d575a8

Please sign in to comment.