From 37244cb9e0ed17de51d8c58b350eeb539654c169 Mon Sep 17 00:00:00 2001 From: m2049r Date: Sun, 10 Jun 2018 10:56:46 +0200 Subject: [PATCH] coinmarketcap for exchange rates (#304) --- .../com/m2049r/xmrwallet/WalletFragment.java | 15 ++- .../ExchangeApiImpl.java | 26 +++-- .../ExchangeRateImpl.java | 43 +++---- .../com/m2049r/xmrwallet/util/Helper.java | 8 ++ .../xmrwallet/widget/ExchangeTextView.java | 6 +- .../m2049r/xmrwallet/widget/ExchangeView.java | 5 +- app/src/main/res/values-de/about.xml | 9 +- app/src/main/res/values-es/about.xml | 9 +- app/src/main/res/values-fr/about.xml | 11 +- app/src/main/res/values-it/about.xml | 20 ++-- app/src/main/res/values-nb/about.xml | 11 +- app/src/main/res/values-zh-rCN/about.xml | 6 +- app/src/main/res/values-zh-rTW/about.xml | 6 +- app/src/main/res/values/about.xml | 11 +- app/src/main/res/values/strings.xml | 31 +++++ .../ExchangeRateTest.java | 108 ++++++++++++++---- 16 files changed, 205 insertions(+), 120 deletions(-) rename app/src/main/java/com/m2049r/xmrwallet/service/exchange/{kraken => coinmarketcap}/ExchangeApiImpl.java (84%) rename app/src/main/java/com/m2049r/xmrwallet/service/exchange/{kraken => coinmarketcap}/ExchangeRateImpl.java (61%) rename app/src/test/java/com/m2049r/xmrwallet/service/exchange/{kraken => coinmarketcap}/ExchangeRateTest.java (56%) diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java index e4d7e18..f9a5be8 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java @@ -43,9 +43,7 @@ import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; -import com.m2049r.xmrwallet.service.exchange.kraken.ExchangeApiImpl; import com.m2049r.xmrwallet.util.Helper; -import com.m2049r.xmrwallet.util.OkHttpClientSingleton; import com.m2049r.xmrwallet.widget.Toolbar; import java.text.NumberFormat; @@ -152,7 +150,7 @@ public class WalletFragment extends Fragment // at this point selection is XMR in case of error String displayB; double amountA = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // crash if this fails! - if (!"XMR".equals(balanceCurrency)) { // not XMR + if (!Helper.CRYPTO.equals(balanceCurrency)) { // not XMR double amountB = amountA * balanceRate; displayB = Helper.getFormattedAmount(amountB, false); } else { // XMR @@ -161,10 +159,10 @@ public class WalletFragment extends Fragment tvBalance.setText(displayB); } - String balanceCurrency = "XMR"; + String balanceCurrency = Helper.CRYPTO; double balanceRate = 1.0; - private final ExchangeApi exchangeApi = new ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient()); + private final ExchangeApi exchangeApi = Helper.getExchangeApi(); void refreshBalance() { if (sCurrency.getSelectedItemPosition() == 0) { // XMR @@ -172,9 +170,10 @@ public class WalletFragment extends Fragment tvBalance.setText(Helper.getFormattedAmount(amountXmr, true)); } else { // not XMR String currency = (String) sCurrency.getSelectedItem(); + Timber.d(currency); if (!currency.equals(balanceCurrency) || (balanceRate <= 0)) { showExchanging(); - exchangeApi.queryExchangeRate("XMR", currency, + exchangeApi.queryExchangeRate(Helper.CRYPTO, currency, new ExchangeCallback() { @Override public void onSuccess(final ExchangeRate exchangeRate) { @@ -230,10 +229,10 @@ public class WalletFragment extends Fragment public void exchange(final ExchangeRate exchangeRate) { hideExchanging(); - if (!"XMR".equals(exchangeRate.getBaseCurrency())) { + if (!Helper.CRYPTO.equals(exchangeRate.getBaseCurrency())) { Timber.e("Not XMR"); sCurrency.setSelection(0, true); - balanceCurrency = "XMR"; + balanceCurrency = Helper.CRYPTO; balanceRate = 1.0; } else { int spinnerPosition = ((ArrayAdapter) sCurrency.getAdapter()).getPosition(exchangeRate.getQuoteCurrency()); diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/exchange/kraken/ExchangeApiImpl.java b/app/src/main/java/com/m2049r/xmrwallet/service/exchange/coinmarketcap/ExchangeApiImpl.java similarity index 84% rename from app/src/main/java/com/m2049r/xmrwallet/service/exchange/kraken/ExchangeApiImpl.java rename to app/src/main/java/com/m2049r/xmrwallet/service/exchange/coinmarketcap/ExchangeApiImpl.java index 8c061c8..5008715 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/service/exchange/kraken/ExchangeApiImpl.java +++ b/app/src/main/java/com/m2049r/xmrwallet/service/exchange/coinmarketcap/ExchangeApiImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 m2049r et al. + * Copyright (c) 2017-2018 m2049r et al. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.m2049r.xmrwallet.service.exchange.kraken; +package com.m2049r.xmrwallet.service.exchange.coinmarketcap; import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; @@ -23,6 +23,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeException; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; +import com.m2049r.xmrwallet.util.Helper; import org.json.JSONArray; import org.json.JSONException; @@ -37,6 +38,7 @@ import okhttp3.Request; import okhttp3.Response; public class ExchangeApiImpl implements ExchangeApi { + static final String CRYPTO_ID = "328"; @NonNull private final OkHttpClient okHttpClient; @@ -52,7 +54,7 @@ public class ExchangeApiImpl implements ExchangeApi { } public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient) { - this(okHttpClient, HttpUrl.parse("https://api.kraken.com/0/public/Ticker")); + this(okHttpClient, HttpUrl.parse("https://api.coinmarketcap.com/v2/ticker/")); } @Override @@ -67,12 +69,12 @@ public class ExchangeApiImpl implements ExchangeApi { boolean inverse = false; String fiat = null; - if (baseCurrency.equals("XMR")) { + if (baseCurrency.equals(Helper.CRYPTO)) { fiat = quoteCurrency; inverse = false; } - if (quoteCurrency.equals("XMR")) { + if (quoteCurrency.equals(Helper.CRYPTO)) { fiat = baseCurrency; inverse = true; } @@ -85,7 +87,8 @@ public class ExchangeApiImpl implements ExchangeApi { final boolean swapAssets = inverse; final HttpUrl url = baseUrl.newBuilder() - .addQueryParameter("pair", "XMR" + fiat) + .addEncodedPathSegments(CRYPTO_ID + "/") + .addQueryParameter("convert", fiat) .build(); final Request httpRequest = createHttpRequest(url); @@ -101,12 +104,12 @@ public class ExchangeApiImpl implements ExchangeApi { if (response.isSuccessful()) { try { final JSONObject json = new JSONObject(response.body().string()); - final JSONArray jsonError = json.getJSONArray("error"); - if (jsonError.length() > 0) { - final String errorMsg = jsonError.getString(0); - callback.onError(new ExchangeException(response.code(), errorMsg)); + final JSONObject metadata = json.getJSONObject("metadata"); + if (!metadata.isNull("error")) { + final String errorMsg = metadata.getString("error"); + callback.onError(new ExchangeException(response.code(), (String) errorMsg)); } else { - final JSONObject jsonResult = json.getJSONObject("result"); + final JSONObject jsonResult = json.getJSONObject("data"); reportSuccess(jsonResult, swapAssets, callback); } } catch (JSONException ex) { @@ -130,7 +133,6 @@ public class ExchangeApiImpl implements ExchangeApi { } } - private Request createHttpRequest(final HttpUrl url) { return new Request.Builder() .url(url) diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/exchange/kraken/ExchangeRateImpl.java b/app/src/main/java/com/m2049r/xmrwallet/service/exchange/coinmarketcap/ExchangeRateImpl.java similarity index 61% rename from app/src/main/java/com/m2049r/xmrwallet/service/exchange/kraken/ExchangeRateImpl.java rename to app/src/main/java/com/m2049r/xmrwallet/service/exchange/coinmarketcap/ExchangeRateImpl.java index 64ba4ad..42a16d7 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/service/exchange/kraken/ExchangeRateImpl.java +++ b/app/src/main/java/com/m2049r/xmrwallet/service/exchange/coinmarketcap/ExchangeRateImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 m2049r et al. + * Copyright (c) 2017-2018 m2049r et al. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.m2049r.xmrwallet.service.exchange.kraken; +package com.m2049r.xmrwallet.service.exchange.coinmarketcap; import android.support.annotation.NonNull; @@ -25,6 +25,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.util.Iterator; import java.util.NoSuchElementException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -37,7 +38,7 @@ class ExchangeRateImpl implements ExchangeRate { @Override public String getServiceName() { - return "kraken.com"; + return "coinmarketcap.com"; } @Override @@ -64,29 +65,21 @@ class ExchangeRateImpl implements ExchangeRate { ExchangeRateImpl(final JSONObject jsonObject, final boolean swapAssets) throws JSONException, ExchangeException { try { - final String key = jsonObject.keys().next(); // we expect only one - Pattern pattern = Pattern.compile("^X(.*?)Z(.*?)$"); - Matcher matcher = pattern.matcher(key); - if (matcher.find()) { - this.baseCurrency = swapAssets ? matcher.group(2) : matcher.group(1); - this.quoteCurrency = swapAssets ? matcher.group(1) : matcher.group(2); - } else { - throw new ExchangeException("no pair returned!"); - } - - JSONObject pair = jsonObject.getJSONObject(key); - JSONArray close = pair.getJSONArray("c"); - String closePrice = close.getString(0); - if (closePrice != null) { - try { - double rate = Double.parseDouble(closePrice); - this.rate = swapAssets ? (1 / rate) : rate; - } catch (NumberFormatException ex) { - throw new ExchangeException(ex.getLocalizedMessage()); - } - } else { - throw new ExchangeException("no close price returned!"); + final String baseC = jsonObject.getString("symbol"); + final JSONObject quotes = jsonObject.getJSONObject("quotes"); + final Iterator keys = quotes.keys(); + String key = null; + // get key which is not USD unless it is the only one + while (keys.hasNext()) { + key = keys.next(); + if (!key.equals("USD")) break; } + final String quoteC = key; + baseCurrency = swapAssets ? quoteC : baseC; + quoteCurrency = swapAssets ? baseC : quoteC; + JSONObject quote = quotes.getJSONObject(key); + double price = quote.getDouble("price"); + this.rate = swapAssets ? (1d / price) : price; } catch (NoSuchElementException ex) { throw new ExchangeException(ex.getLocalizedMessage()); } diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java index fed1bb8..025af03 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java @@ -56,6 +56,7 @@ import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.model.NetworkType; import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.WalletManager; +import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; import java.io.File; import java.io.IOException; @@ -72,6 +73,8 @@ import okhttp3.HttpUrl; import timber.log.Timber; public class Helper { + static public final String CRYPTO = "XMR"; + static private final String WALLET_DIR = "monerujo" + (BuildConfig.DEBUG ? "-debug" : ""); static private final String HOME_DIR = "monero" + (BuildConfig.DEBUG ? "-debug" : ""); @@ -523,4 +526,9 @@ public class Helper { return false; } } + + static public ExchangeApi getExchangeApi() { + return new com.m2049r.xmrwallet.service.exchange.coinmarketcap.ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient()); + + } } diff --git a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeTextView.java b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeTextView.java index 25a1225..bfe49e5 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeTextView.java +++ b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeTextView.java @@ -36,9 +36,7 @@ import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; -import com.m2049r.xmrwallet.service.exchange.kraken.ExchangeApiImpl; import com.m2049r.xmrwallet.util.Helper; -import com.m2049r.xmrwallet.util.OkHttpClientSingleton; import java.util.Locale; @@ -250,7 +248,7 @@ public class ExchangeTextView extends LinearLayout } } - private final ExchangeApi exchangeApi = new ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient()); + private final ExchangeApi exchangeApi = Helper.getExchangeApi(); void startExchange() { showProgress(); @@ -458,4 +456,4 @@ public class ExchangeTextView extends LinearLayout tvAmountA.setText(null); doExchange(); } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeView.java b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeView.java index bf2ff7f..203ed09 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeView.java +++ b/app/src/main/java/com/m2049r/xmrwallet/widget/ExchangeView.java @@ -42,9 +42,7 @@ import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; -import com.m2049r.xmrwallet.service.exchange.kraken.ExchangeApiImpl; import com.m2049r.xmrwallet.util.Helper; -import com.m2049r.xmrwallet.util.OkHttpClientSingleton; import java.util.Locale; @@ -315,12 +313,13 @@ public class ExchangeView extends LinearLayout } } - private final ExchangeApi exchangeApi = new ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient()); + private final ExchangeApi exchangeApi = Helper.getExchangeApi(); void startExchange() { showProgress(); String currencyA = (String) sCurrencyA.getSelectedItem(); String currencyB = (String) sCurrencyB.getSelectedItem(); + exchangeApi.queryExchangeRate(currencyA, currencyB, new ExchangeCallback() { @Override diff --git a/app/src/main/res/values-de/about.xml b/app/src/main/res/values-de/about.xml index c2853bf..52e6f88 100644 --- a/app/src/main/res/values-de/about.xml +++ b/app/src/main/res/values-de/about.xml @@ -29,11 +29,10 @@ von Transaktionen lokal gesammelt und verarbeitet und verschlüsselt in das Monero-Netzwerk übertragen.

Andere persönliche Daten werden von der App nicht gesammelt.

-

Wenn du den USD/EUR Umrechner (optional) nutzt fragt Monerujo - den aktuellen Kurs über die öffentliche Schnittstelle von kraken.com ab. - Siehe dir ihre Datenschutzerklärung unter https://www.kraken.com/legal/privacy für - Details darüber an, wie Daten in deinen Anfragen gesammelt werden (insbesondere der - Abschnitt "Information We Collect Automatically").

+

Wenn du den Umrechner (optional) nutzt fragt Monerujo + den aktuellen Kurs über die öffentliche Schnittstelle von coinmarketcap.com ab. + Siehe dir ihre Datenschutzerklärung unter https://coinmarketcap.com/privacy für + Details darüber an, wie Daten in deinen Anfragen gesammelt werden.

Wenn du die App zum Bezahlen an BTC-Adressen verwendest, verwendest du den Dienst XMR.TO. Weitere Informationen findest du in den Datenschutzerklärung unter https://xmr.to/. Monerujo schickt dem Anbieter die BTC Zieladresse und den Betrag. diff --git a/app/src/main/res/values-es/about.xml b/app/src/main/res/values-es/about.xml index ddd25b0..531aa40 100644 --- a/app/src/main/res/values-es/about.xml +++ b/app/src/main/res/values-es/about.xml @@ -29,11 +29,10 @@ Monero de forma cifrada.

Otros datos personales no son recopilados por la app.

-

Si utiliza la funcionalidad de cambio USD/EUR (opcional), monerujo obtiene la tasa - de cambio a través de la API pública de kraken.com. - Vea su política de privadad en https://www.kraken.com/legal/privacy para conocer más - detalles acerca de como se recopilan los datos de sus peticiones (especialmente la sección - "Innformation We Collect Automatically").

+

Si utiliza la funcionalidad de cambio (opcional), monerujo obtiene la tasa + de cambio a través de la API pública de coinmarketcap.com. + Vea su política de privadad en https://coinmarketcap.com/privacy para conocer más + detalles acerca de como se recopilan los datos de sus peticiones.

Permisos de la App