From 7fd08a16b6f026c57238d6612342094a2b263e52 Mon Sep 17 00:00:00 2001 From: rafael_xmr Date: Fri, 9 Oct 2026 07:41:02 -0300 Subject: [PATCH] feat: onramper api v2 (#3686) --- lib/buy/onramper/onramper_buy_provider.dart | 47 +++++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/buy/onramper/onramper_buy_provider.dart b/lib/buy/onramper/onramper_buy_provider.dart index b1a855f73..60e2e9d29 100644 --- a/lib/buy/onramper/onramper_buy_provider.dart +++ b/lib/buy/onramper/onramper_buy_provider.dart @@ -15,6 +15,15 @@ import 'package:cw_core/wallet_base.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; +class OnramperSignatureException implements Exception { + OnramperSignatureException(this.message); + + final String message; + + @override + String toString() => "OnramperSignatureException: $message"; +} + class OnRamperBuyProvider extends BuyProvider { OnRamperBuyProvider({required WalletBase wallet, bool isTestEnvironment = false}) : super( @@ -27,6 +36,7 @@ class OnRamperBuyProvider extends BuyProvider { notSupportedFiat: _notSupportedFiat, notSupportedCrypto: _notSupportedCrypto)); static const _baseUrl = 'buy.onramper.com'; + static const _stagingBaseUrl = 'buy.onramper.dev'; static const _baseApiUrl = 'api.onramper.com'; static const _cIdBaseUrl = 'exchange-helper.cakewallet.com'; static const quotes = '/quotes'; @@ -59,21 +69,30 @@ class OnRamperBuyProvider extends BuyProvider { @override bool get isAggregator => true; - Future getOnramperSignature(String query) async { - final uri = Uri.https(_cIdBaseUrl, "/api/onramper"); + /// Asks the exchange helper to sign the widget URL fields (Onramper Signature V2). + /// Returns the extra query parameters to append to the widget URL: the `sigV2*` params and the + /// `endUserIpHash` the helper bound the session to (it is part of the signature). + Future> getOnramperSignatureParams(Map fields) async { + final uri = Uri.https(_cIdBaseUrl, "/api/onramper/v2"); final response = await ProxyWrapper().post( clearnetUri: uri, - headers: {'Content-Type': 'application/json', 'x-api-key': _exchangeHelperApiKey}, - body: json.encode({'query': query}), + headers: {"Content-Type": "application/json", "x-api-key": _exchangeHelperApiKey}, + body: json.encode({"fields": fields}), ); - if (response.statusCode == 200) { - return (jsonDecode(response.body) as Map)['signature'] as String; - } else { - throw Exception( - 'Provider currently unavailable. Status: ${response.statusCode} ${response.body}'); + if (response.statusCode != 200) { + throw OnramperSignatureException( + "Provider currently unavailable. Status: ${response.statusCode} ${response.body}"); } + + final body = jsonDecode(response.body) as Map; + final signature = body["signature"] as Map; + + return { + ...signature.map((key, value) => MapEntry(key, value as String)), + "endUserIpHash": body["endUserIpHash"] as String, + }; } Future getRecommendedPaymentType(bool isBuyAction) async { @@ -280,10 +299,11 @@ class OnRamperBuyProvider extends BuyProvider { final networkWallets = '${_tagToNetwork(quote.cryptoCurrency.tag ?? quote.cryptoCurrency.title).toLowerCase()}:$cryptoCurrencyAddress'; - final signature = await getOnramperSignature("networkWallets=$networkWallets"); + final signedFields = {"apiKey": _apiKey, "networkWallets": networkWallets}; + final signatureParams = await getOnramperSignatureParams(signedFields); - final uri = Uri.https(_baseUrl, '', { - 'apiKey': _apiKey, + final uri = Uri.https(isTestEnvironment ? _stagingBaseUrl : _baseUrl, '', { + ...signedFields, 'txnType': actionType, 'txnFiat': quote.fiatCurrency.name, 'txnCrypto': defaultCrypto, @@ -291,7 +311,6 @@ class OnRamperBuyProvider extends BuyProvider { 'skipTransactionScreen': "true", if (paymentMethod != null) 'txnPaymentMethod': paymentMethod, 'txnOnramp': quote.rampId, - 'networkWallets': networkWallets, 'supportSwap': "false", 'primaryColor': primaryColor, 'secondaryColor': secondaryColor, @@ -299,7 +318,7 @@ class OnRamperBuyProvider extends BuyProvider { 'primaryTextColor': primaryTextColor, 'secondaryTextColor': secondaryTextColor, 'cardColor': cardColor, - 'signature': signature, + ...signatureParams, }); if (await canLaunchUrl(uri)) {