coinmarketcap for exchange rates (#304)

This commit is contained in:
m2049r 2018-06-10 10:56:46 +02:00 committed by GitHub
parent 843566b820
commit 37244cb9e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 205 additions and 120 deletions

View File

@ -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.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; 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.Helper;
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
import com.m2049r.xmrwallet.widget.Toolbar; import com.m2049r.xmrwallet.widget.Toolbar;
import java.text.NumberFormat; import java.text.NumberFormat;
@ -152,7 +150,7 @@ public class WalletFragment extends Fragment
// at this point selection is XMR in case of error // at this point selection is XMR in case of error
String displayB; String displayB;
double amountA = Double.parseDouble(Wallet.getDisplayAmount(unlockedBalance)); // crash if this fails! 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; double amountB = amountA * balanceRate;
displayB = Helper.getFormattedAmount(amountB, false); displayB = Helper.getFormattedAmount(amountB, false);
} else { // XMR } else { // XMR
@ -161,10 +159,10 @@ public class WalletFragment extends Fragment
tvBalance.setText(displayB); tvBalance.setText(displayB);
} }
String balanceCurrency = "XMR"; String balanceCurrency = Helper.CRYPTO;
double balanceRate = 1.0; double balanceRate = 1.0;
private final ExchangeApi exchangeApi = new ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient()); private final ExchangeApi exchangeApi = Helper.getExchangeApi();
void refreshBalance() { void refreshBalance() {
if (sCurrency.getSelectedItemPosition() == 0) { // XMR if (sCurrency.getSelectedItemPosition() == 0) { // XMR
@ -172,9 +170,10 @@ public class WalletFragment extends Fragment
tvBalance.setText(Helper.getFormattedAmount(amountXmr, true)); tvBalance.setText(Helper.getFormattedAmount(amountXmr, true));
} else { // not XMR } else { // not XMR
String currency = (String) sCurrency.getSelectedItem(); String currency = (String) sCurrency.getSelectedItem();
Timber.d(currency);
if (!currency.equals(balanceCurrency) || (balanceRate <= 0)) { if (!currency.equals(balanceCurrency) || (balanceRate <= 0)) {
showExchanging(); showExchanging();
exchangeApi.queryExchangeRate("XMR", currency, exchangeApi.queryExchangeRate(Helper.CRYPTO, currency,
new ExchangeCallback() { new ExchangeCallback() {
@Override @Override
public void onSuccess(final ExchangeRate exchangeRate) { public void onSuccess(final ExchangeRate exchangeRate) {
@ -230,10 +229,10 @@ public class WalletFragment extends Fragment
public void exchange(final ExchangeRate exchangeRate) { public void exchange(final ExchangeRate exchangeRate) {
hideExchanging(); hideExchanging();
if (!"XMR".equals(exchangeRate.getBaseCurrency())) { if (!Helper.CRYPTO.equals(exchangeRate.getBaseCurrency())) {
Timber.e("Not XMR"); Timber.e("Not XMR");
sCurrency.setSelection(0, true); sCurrency.setSelection(0, true);
balanceCurrency = "XMR"; balanceCurrency = Helper.CRYPTO;
balanceRate = 1.0; balanceRate = 1.0;
} else { } else {
int spinnerPosition = ((ArrayAdapter) sCurrency.getAdapter()).getPosition(exchangeRate.getQuoteCurrency()); int spinnerPosition = ((ArrayAdapter) sCurrency.getAdapter()).getPosition(exchangeRate.getQuoteCurrency());

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -14,7 +14,7 @@
* limitations under the License. * 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.NonNull;
import android.support.annotation.VisibleForTesting; 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.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeException; import com.m2049r.xmrwallet.service.exchange.api.ExchangeException;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
import com.m2049r.xmrwallet.util.Helper;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -37,6 +38,7 @@ import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
public class ExchangeApiImpl implements ExchangeApi { public class ExchangeApiImpl implements ExchangeApi {
static final String CRYPTO_ID = "328";
@NonNull @NonNull
private final OkHttpClient okHttpClient; private final OkHttpClient okHttpClient;
@ -52,7 +54,7 @@ public class ExchangeApiImpl implements ExchangeApi {
} }
public ExchangeApiImpl(@NonNull final OkHttpClient okHttpClient) { 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 @Override
@ -67,12 +69,12 @@ public class ExchangeApiImpl implements ExchangeApi {
boolean inverse = false; boolean inverse = false;
String fiat = null; String fiat = null;
if (baseCurrency.equals("XMR")) { if (baseCurrency.equals(Helper.CRYPTO)) {
fiat = quoteCurrency; fiat = quoteCurrency;
inverse = false; inverse = false;
} }
if (quoteCurrency.equals("XMR")) { if (quoteCurrency.equals(Helper.CRYPTO)) {
fiat = baseCurrency; fiat = baseCurrency;
inverse = true; inverse = true;
} }
@ -85,7 +87,8 @@ public class ExchangeApiImpl implements ExchangeApi {
final boolean swapAssets = inverse; final boolean swapAssets = inverse;
final HttpUrl url = baseUrl.newBuilder() final HttpUrl url = baseUrl.newBuilder()
.addQueryParameter("pair", "XMR" + fiat) .addEncodedPathSegments(CRYPTO_ID + "/")
.addQueryParameter("convert", fiat)
.build(); .build();
final Request httpRequest = createHttpRequest(url); final Request httpRequest = createHttpRequest(url);
@ -101,12 +104,12 @@ public class ExchangeApiImpl implements ExchangeApi {
if (response.isSuccessful()) { if (response.isSuccessful()) {
try { try {
final JSONObject json = new JSONObject(response.body().string()); final JSONObject json = new JSONObject(response.body().string());
final JSONArray jsonError = json.getJSONArray("error"); final JSONObject metadata = json.getJSONObject("metadata");
if (jsonError.length() > 0) { if (!metadata.isNull("error")) {
final String errorMsg = jsonError.getString(0); final String errorMsg = metadata.getString("error");
callback.onError(new ExchangeException(response.code(), errorMsg)); callback.onError(new ExchangeException(response.code(), (String) errorMsg));
} else { } else {
final JSONObject jsonResult = json.getJSONObject("result"); final JSONObject jsonResult = json.getJSONObject("data");
reportSuccess(jsonResult, swapAssets, callback); reportSuccess(jsonResult, swapAssets, callback);
} }
} catch (JSONException ex) { } catch (JSONException ex) {
@ -130,7 +133,6 @@ public class ExchangeApiImpl implements ExchangeApi {
} }
} }
private Request createHttpRequest(final HttpUrl url) { private Request createHttpRequest(final HttpUrl url) {
return new Request.Builder() return new Request.Builder()
.url(url) .url(url)

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -14,7 +14,7 @@
* limitations under the License. * 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.NonNull;
@ -25,6 +25,7 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Iterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -37,7 +38,7 @@ class ExchangeRateImpl implements ExchangeRate {
@Override @Override
public String getServiceName() { public String getServiceName() {
return "kraken.com"; return "coinmarketcap.com";
} }
@Override @Override
@ -64,29 +65,21 @@ class ExchangeRateImpl implements ExchangeRate {
ExchangeRateImpl(final JSONObject jsonObject, final boolean swapAssets) throws JSONException, ExchangeException { ExchangeRateImpl(final JSONObject jsonObject, final boolean swapAssets) throws JSONException, ExchangeException {
try { try {
final String key = jsonObject.keys().next(); // we expect only one final String baseC = jsonObject.getString("symbol");
Pattern pattern = Pattern.compile("^X(.*?)Z(.*?)$"); final JSONObject quotes = jsonObject.getJSONObject("quotes");
Matcher matcher = pattern.matcher(key); final Iterator<String> keys = quotes.keys();
if (matcher.find()) { String key = null;
this.baseCurrency = swapAssets ? matcher.group(2) : matcher.group(1); // get key which is not USD unless it is the only one
this.quoteCurrency = swapAssets ? matcher.group(1) : matcher.group(2); while (keys.hasNext()) {
} else { key = keys.next();
throw new ExchangeException("no pair returned!"); if (!key.equals("USD")) break;
}
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 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) { } catch (NoSuchElementException ex) {
throw new ExchangeException(ex.getLocalizedMessage()); throw new ExchangeException(ex.getLocalizedMessage());
} }

View File

@ -56,6 +56,7 @@ import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.model.NetworkType; import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -72,6 +73,8 @@ import okhttp3.HttpUrl;
import timber.log.Timber; import timber.log.Timber;
public class Helper { public class Helper {
static public final String CRYPTO = "XMR";
static private final String WALLET_DIR = "monerujo" + (BuildConfig.DEBUG ? "-debug" : ""); static private final String WALLET_DIR = "monerujo" + (BuildConfig.DEBUG ? "-debug" : "");
static private final String HOME_DIR = "monero" + (BuildConfig.DEBUG ? "-debug" : ""); static private final String HOME_DIR = "monero" + (BuildConfig.DEBUG ? "-debug" : "");
@ -523,4 +526,9 @@ public class Helper {
return false; return false;
} }
} }
static public ExchangeApi getExchangeApi() {
return new com.m2049r.xmrwallet.service.exchange.coinmarketcap.ExchangeApiImpl(OkHttpClientSingleton.getOkHttpClient());
}
} }

View File

@ -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.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; 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.Helper;
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
import java.util.Locale; 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() { void startExchange() {
showProgress(); showProgress();

View File

@ -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.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; 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.Helper;
import com.m2049r.xmrwallet.util.OkHttpClientSingleton;
import java.util.Locale; 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() { void startExchange() {
showProgress(); showProgress();
String currencyA = (String) sCurrencyA.getSelectedItem(); String currencyA = (String) sCurrencyA.getSelectedItem();
String currencyB = (String) sCurrencyB.getSelectedItem(); String currencyB = (String) sCurrencyB.getSelectedItem();
exchangeApi.queryExchangeRate(currencyA, currencyB, exchangeApi.queryExchangeRate(currencyA, currencyB,
new ExchangeCallback() { new ExchangeCallback() {
@Override @Override

View File

@ -29,11 +29,10 @@
von Transaktionen lokal gesammelt und verarbeitet und verschlüsselt in das Monero-Netzwerk übertragen. von Transaktionen lokal gesammelt und verarbeitet und verschlüsselt in das Monero-Netzwerk übertragen.
</p> </p>
<p>Andere persönliche Daten werden von der App nicht gesammelt.</p> <p>Andere persönliche Daten werden von der App nicht gesammelt.</p>
<p>Wenn du den USD/EUR Umrechner (optional) nutzt fragt Monerujo <p>Wenn du den Umrechner (optional) nutzt fragt Monerujo
den aktuellen Kurs über die öffentliche Schnittstelle von kraken.com ab. den aktuellen Kurs über die öffentliche Schnittstelle von coinmarketcap.com ab.
Siehe dir ihre Datenschutzerklärung unter https://www.kraken.com/legal/privacy für Siehe dir ihre Datenschutzerklärung unter https://coinmarketcap.com/privacy für
Details darüber an, wie Daten in deinen Anfragen gesammelt werden (insbesondere der Details darüber an, wie Daten in deinen Anfragen gesammelt werden.</p>
Abschnitt "Information We Collect Automatically").</p>
<p>Wenn du die App zum Bezahlen an BTC-Adressen verwendest, verwendest du den Dienst XMR.TO. <p>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/. Weitere Informationen findest du in den Datenschutzerklärung unter https://xmr.to/.
Monerujo schickt dem Anbieter die BTC Zieladresse und den Betrag. Monerujo schickt dem Anbieter die BTC Zieladresse und den Betrag.

View File

@ -29,11 +29,10 @@
Monero de forma cifrada. Monero de forma cifrada.
</p> </p>
<p>Otros datos personales no son recopilados por la app.</p> <p>Otros datos personales no son recopilados por la app.</p>
<p>Si utiliza la funcionalidad de cambio USD/EUR (opcional), monerujo obtiene la tasa <p>Si utiliza la funcionalidad de cambio (opcional), monerujo obtiene la tasa
de cambio a través de la API pública de kraken.com. de cambio a través de la API pública de coinmarketcap.com.
Vea su política de privadad en https://www.kraken.com/legal/privacy para conocer más 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 (especialmente la sección detalles acerca de como se recopilan los datos de sus peticiones.</p>
"Innformation We Collect Automatically").</p>
<h2>Permisos de la App</h2> <h2>Permisos de la App</h2>
<ul> <ul>
<li>INTERNET : Conectar a la red de Monero a través de un Daemon Nodo de Monero</li> <li>INTERNET : Conectar a la red de Monero a través de un Daemon Nodo de Monero</li>

View File

@ -31,11 +31,10 @@
réseau Monero sous une forme chiffrée. réseau Monero sous une forme chiffrée.
</p> </p>
<p>Aucune autre donnée personnelle nest collectée par lapplication.</p> <p>Aucune autre donnée personnelle nest collectée par lapplication.</p>
<p>Si vous utilisez la fonction (optionnelle) de change USD/EUR, monerujo récupère le <p>Si vous utilisez la fonction (optionnelle) de change, monerujo récupère le
taux de change via lAPI publique de kraken.com. taux de change via lAPI publique de coinmarketcap.com.
Consultez leur politique de confidentialité sur https://www.kraken.com/legal/privacy Consultez leur politique de confidentialité sur https://coinmarketcap.com/privacy
pour des détails sur la façon dont les données de vos requêtes sont collectées pour des détails sur la façon dont les données de vos requêtes sont collectées.</p>
(particulièrement la rubrique "Information We Collect Automatically").</p>
<p>Si vous utilisez lapplication pour payer à une adresse BTC, vous utiliserez <p>Si vous utilisez lapplication pour payer à une adresse BTC, vous utiliserez
le service XMR.TO. Consultez leur politique de confidentialité sur https://xmr.to/ le service XMR.TO. Consultez leur politique de confidentialité sur https://xmr.to/
pour plus de détails. Monerujo leur transmet ladresse de destination BTC et le pour plus de détails. Monerujo leur transmet ladresse de destination BTC et le

View File

@ -15,35 +15,35 @@
<string name="privacy_policy"><![CDATA[ <string name="privacy_policy"><![CDATA[
<h1>Politica per la Privacy</h1> <h1>Politica per la Privacy</h1>
<p>Questa pagina ti informa sulla nostra politica riguardante la raccolta, l'utilizzo e la rivelazione di informazioni personali che riceviamo dagli utenti della nostra app (monerujo: Portafoglio Monero). <p>Questa pagina ti informa sulla nostra politica riguardante la raccolta, l\'utilizzo e la rivelazione di informazioni personali che riceviamo dagli utenti della nostra app (monerujo: Portafoglio Monero).
</p> </p>
<p>Usando questa app, acconsenti alla raccolta e all'utilizzo delle informazioni in accordo con questa politica. <p>Usando questa app, acconsenti alla raccolta e all\'utilizzo delle informazioni in accordo con questa politica.
</p> </p>
<h2>Dati raccolti</h2> <h2>Dati raccolti</h2>
<p>Per "dato personale" si intende ogni tipo di dato grazie al quale è possibile identificare un individuo. <p>Per "dato personale" si intende ogni tipo di dato grazie al quale è possibile identificare un individuo.
</p> </p>
<p>Le chiavi e gli indirizzi pubblici di Monero vengono raccolti e processati dall'app localmente con lo scopo di processare le transazioni e vengono trasmessi all'interno della rete Monero in modo cifrato. <p>Le chiavi e gli indirizzi pubblici di Monero vengono raccolti e processati dall\'app localmente con lo scopo di processare le transazioni e vengono trasmessi all\'interno della rete Monero in modo cifrato.
</p> </p>
<p>Altri dati personali non sono raccolti dall'app.</p> <p>Altri dati personali non sono raccolti dall\'app.</p>
<p>Se usi la funzionalità (opzionale) del cambio USD/EUR, monerujo recupera il tasso di cambio attraverso le API pubbliche di kraken.com. <p>Se usi la funzionalità (opzionale) del cambio, monerujo recupera il tasso di cambio attraverso le API pubbliche di coinmarketcap.com.
Controlla la loro politica per la privacy (in lingua inglese) su https://www.kraken.com/legal/privacy per conoscere i dettagli su come vengono raccolti i dati nelle tue richieste (specialmente la sezione "Information We Collect Automatically" - "Informazioni che raccogliamo in modo automatico).</p> Controlla la loro politica per la privacy (in lingua inglese) su https://coinmarketcap.com/privacy per conoscere i dettagli su come vengono raccolti i dati nelle tue richieste.</p>
<p>Se utilizzi l'app per effettuare pagamenti ad indirizzi BTC, stai usando il servizio XMR.TO. <p>Se utilizzi l'app per effettuare pagamenti ad indirizzi BTC, stai usando il servizio XMR.TO.
Controlla la loro politica per la privacy (in lingua inglese) su https://xmr.to/ per conoscere i dettagli. Monerujo invia a loro l'indirizzo di destinazione BTC e l'ammontare della transazione. Anche il tuo IP potrebbe essere raccolto.</p> Controlla la loro politica per la privacy (in lingua inglese) su https://xmr.to/ per conoscere i dettagli. Monerujo invia a loro l'indirizzo di destinazione BTC e l'ammontare della transazione. Anche il tuo IP potrebbe essere raccolto.</p>
<h2>Permessi app</h2> <h2>Permessi app</h2>
<ul> <ul>
<li>INTERNET : Connessione alla rete Monero attraverso un nodo </li> <li>INTERNET : Connessione alla rete Monero attraverso un nodo </li>
<li>READ_EXTERNAL_STORAGE : Legge i file di portafoglio salvati all'interno del dispositivo</li> <li>READ_EXTERNAL_STORAGE : Legge i file di portafoglio salvati all\'interno del dispositivo</li>
<li>WRITE_EXTERNAL_STORAGE : Scrive i file di portafoglio salvati all'interno del dispositivo</li> <li>WRITE_EXTERNAL_STORAGE : Scrive i file di portafoglio salvati all\'interno del dispositivo</li>
<li>WAKE_LOCK : Tiene il dispositivo sveglio durante la sincronizzazione</li> <li>WAKE_LOCK : Tiene il dispositivo sveglio durante la sincronizzazione</li>
<li>CAMERA : Scansione codici QR di indirizzi Monero</li> <li>CAMERA : Scansione codici QR di indirizzi Monero</li>
</ul> </ul>
<h2>Modifica a questa Politica per la Privacy</h2> <h2>Modifica a questa Politica per la Privacy</h2>
<p>Potremmo aggiorare questa politica per la privacy di volta in volta. Ti invieremo una notifica su ciò che è cambiato pubblicando la nuova politica per la privacy all'interno dell'app e sul sito (www.monerujo.io) <p>Potremmo aggiorare questa politica per la privacy di volta in volta. Ti invieremo una notifica su ciò che è cambiato pubblicando la nuova politica per la privacy all\'interno dell\'app e sul sito (www.monerujo.io)
Sei invitato a rivedere periodicamente questa politica per la privacy per controllarne i cambiamenti. Sei invitato a rivedere periodicamente questa politica per la privacy per controllarne i cambiamenti.
<p>Questa politica per la privacy è stata aggiornata il 10 novembre 2017. <p>Questa politica per la privacy è stata aggiornata il 10 novembre 2017.
</p> </p>
<h2>Contattaci</h2> <h2>Contattaci</h2>
<p>Se hai dubbi o domande sulla nostra politica per la privacy, oppure su come i tuoi dati vengono raccolti e processati, contattaci all'indirizzo email privacy@monerujo.io. <p>Se hai dubbi o domande sulla nostra politica per la privacy, oppure su come i tuoi dati vengono raccolti e processati, contattaci all\'indirizzo email privacy@monerujo.io.
</p> </p>
]]></string> ]]></string>
</resources> </resources>

View File

@ -30,11 +30,10 @@
in encrypted form. in encrypted form.
</p> </p>
<p>Other personal data is not collected by the app.</p> <p>Other personal data is not collected by the app.</p>
<p>If you use the USD/EUR exchange (optional) functionality, monerujo fetches the exchange <p>If you use the exchange (optional) functionality, monerujo fetches the exchange
rate through the public API of kraken.com. rate through the public API of coinmarketcap.com.
See their privacy policy at https://www.kraken.com/legal/privacy for See their privacy policy at https://coinmarketcap.com/privacy for
details on how data in your requests is collected (especially the details on how data in your requests is collected.</p>
section "Information We Collect Automatically").</p>
<p>If you use the app to pay to BTC addresses, you will be using the XMR.TO service. <p>If you use the app to pay to BTC addresses, you will be using the XMR.TO service.
See their privacy policy at https://xmr.to/ for details. Monerujo send them the BTC See their privacy policy at https://xmr.to/ for details. Monerujo send them the BTC
destination address and amount. Your IP will also be collectable.</p> destination address and amount. Your IP will also be collectable.</p>

View File

@ -22,9 +22,9 @@
<p>Monerujo 只会在本地端使用您的 Monero 私钥以及公开地址执行必要的处理,并在加密后发送至 <p>Monerujo 只会在本地端使用您的 Monero 私钥以及公开地址执行必要的处理,并在加密后发送至
Monero 网络进行交易。</p> Monero 网络进行交易。</p>
<p>其他个人信息都不会被 monerujo 收集。</p> <p>其他个人信息都不会被 monerujo 收集。</p>
<p>如果你使用 USD/EUR 外汇的功能(可选用)monerujo 將通过 kraken.com 的公开 <p>如果你使用外汇的功能(可选用)monerujo 將通过 coinmarketcap.com 的公开
API 抓取当前汇率。如果你想了解自己被收集的信息如何被使用,请访问 https://www.kraken.com/legal/privacy API 抓取当前汇率。如果你想了解自己被收集的信息如何被使用,请访问 https://coinmarketcap.com/privacy
查看他们的隐私政策特別是「Information We Collect Automatically」章节</p> 查看他们的隐私政策。</p>
<p>如果你想使用本 App 支付款项至比特币地址,您将使用 XMR.TO 所提供的服务。Monerujo <p>如果你想使用本 App 支付款项至比特币地址,您将使用 XMR.TO 所提供的服务。Monerujo
将发送比特币的目标地址以及金额至 XMR.TO您的 IP 在此时也可能会被收集。详情请至 https://xmr.to/ 将发送比特币的目标地址以及金额至 XMR.TO您的 IP 在此时也可能会被收集。详情请至 https://xmr.to/
查看他们的隐私政策。</p> 查看他们的隐私政策。</p>

View File

@ -22,9 +22,9 @@
<p>Monerujo 只會在本地端使用您的 Monero 金鑰以及公開地址執行必要的處理,並在加密後發送至 <p>Monerujo 只會在本地端使用您的 Monero 金鑰以及公開地址執行必要的處理,並在加密後發送至
Monero 網路進行交易。</p> Monero 網路進行交易。</p>
<p>其餘的個人資料都不會被 monerujo 收集。</p> <p>其餘的個人資料都不會被 monerujo 收集。</p>
<p>倘若您有使用 USD/EUR 匯兌的功能(可選用)monerujo 將透過 kraken.com 的公開 <p>倘若您有使用匯兌的功能(可選用)monerujo 將透過 coinmarketcap.com 的公開
API 抓取目前的匯率。若欲了解您要求的資料會如何被收集及使用,請至 https://www.kraken.com/legal/privacy API 抓取目前的匯率。若欲了解您要求的資料會如何被收集及使用,請至 https://coinmarketcap.com/privacy
觀看他們的隱私權政策特別是「Information We Collect Automatically」章節</p> 觀看他們的隱私權政策。</p>
<p>若您想使用本 App 支付款項至 BTC 位址,您將使用 XMR.TO 所提供的服務。Monerujo <p>若您想使用本 App 支付款項至 BTC 位址,您將使用 XMR.TO 所提供的服務。Monerujo
將發送 BTC 目標位址以及金額至 XMR.TO您的 IP 在此時也可能會被收集。詳情請至 https://xmr.to/ 將發送 BTC 目標位址以及金額至 XMR.TO您的 IP 在此時也可能會被收集。詳情請至 https://xmr.to/
觀看他們的隱私權政策。</p> 觀看他們的隱私權政策。</p>

View File

@ -30,11 +30,10 @@
in encrypted form. in encrypted form.
</p> </p>
<p>Other personal data is not collected by the app.</p> <p>Other personal data is not collected by the app.</p>
<p>If you use the USD/EUR exchange (optional) functionality, monerujo fetches the exchange <p>If you use the exchange (optional) functionality, monerujo fetches the exchange
rate through the public API of kraken.com. rate through the public API of coinmarketcap.com.
See their privacy policy at https://www.kraken.com/legal/privacy for See their privacy policy at https://coinmarketcap.com/privacy for
details on how data in your requests is collected (especially the details on how data in your requests is collected.</p>
section "Information We Collect Automatically").</p>
<p>If you use the app to pay to BTC addresses, you will be using the XMR.TO service. <p>If you use the app to pay to BTC addresses, you will be using the XMR.TO service.
See their privacy policy at https://xmr.to/ for details. Monerujo send them the BTC See their privacy policy at https://xmr.to/ for details. Monerujo send them the BTC
destination address and amount. Your IP will also be collectable.</p> destination address and amount. Your IP will also be collectable.</p>

View File

@ -321,6 +321,37 @@
<item>XMR</item> <item>XMR</item>
<item>EUR</item> <item>EUR</item>
<item>USD</item> <item>USD</item>
<item>JPY</item>
<item>GBP</item>
<item>CHF</item>
<item>CAD</item>
<item>AUD</item>
<item>ZAR</item>
<item>BRL</item>
<item>CLP</item>
<item>CNY</item>
<item>CZK</item>
<item>DKK</item>
<item>HKD</item>
<item>HUF</item>
<item>IDR</item>
<item>ILS</item>
<item>INR</item>
<item>KRW</item>
<item>MXN</item>
<item>MYR</item>
<item>NOK</item>
<item>NZD</item>
<item>PHP</item>
<item>PKR</item>
<item>PLN</item>
<item>RUB</item>
<item>SEK</item>
<item>SGD</item>
<item>THB</item>
<item>TRY</item>
<item>TWD</item>
</string-array> </string-array>
<string name="fab_create_new">Create new wallet</string> <string name="fab_create_new">Create new wallet</string>

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet.service.exchange.kraken; package com.m2049r.xmrwallet.service.exchange.coinmarketcap;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi; import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
@ -73,7 +73,7 @@ public class ExchangeRateTest {
public void queryExchangeRate_shouldBeGetMethod() public void queryExchangeRate_shouldBeGetMethod()
throws InterruptedException, TimeoutException { throws InterruptedException, TimeoutException {
exchangeApi.queryExchangeRate("XMR", "USD", mockExchangeCallback); exchangeApi.queryExchangeRate("XMR", "EUR", mockExchangeCallback);
RecordedRequest request = mockWebServer.takeRequest(); RecordedRequest request = mockWebServer.takeRequest();
assertEquals("GET", request.getMethod()); assertEquals("GET", request.getMethod());
@ -83,18 +83,46 @@ public class ExchangeRateTest {
public void queryExchangeRate_shouldHavePairInUrl() public void queryExchangeRate_shouldHavePairInUrl()
throws InterruptedException, TimeoutException { throws InterruptedException, TimeoutException {
exchangeApi.queryExchangeRate("XMR", "USD", mockExchangeCallback); exchangeApi.queryExchangeRate("XMR", "EUR", mockExchangeCallback);
RecordedRequest request = mockWebServer.takeRequest(); RecordedRequest request = mockWebServer.takeRequest();
assertEquals("/?pair=XMRUSD", request.getPath()); assertEquals("/328/?convert=EUR", request.getPath());
} }
@Test @Test
public void queryExchangeRate_wasSuccessfulShouldRespondWithRate() public void queryExchangeRate_wasSuccessfulShouldRespondWithRate()
throws InterruptedException, JSONException, TimeoutException { throws InterruptedException, JSONException, TimeoutException {
final String base = "XMR"; final String base = "XMR";
final String quote = "EUR";
final double rate = 1.56;
MockResponse jsonMockResponse = new MockResponse().setBody(
createMockExchangeRateResponse(base, quote, rate));
mockWebServer.enqueue(jsonMockResponse);
exchangeApi.queryExchangeRate(base, quote, new ExchangeCallback() {
@Override
public void onSuccess(final ExchangeRate exchangeRate) {
waiter.assertEquals(exchangeRate.getBaseCurrency(), base);
waiter.assertEquals(exchangeRate.getQuoteCurrency(), quote);
waiter.assertEquals(exchangeRate.getRate(), rate);
waiter.resume();
}
@Override
public void onError(final Exception e) {
waiter.fail(e);
waiter.resume();
}
});
waiter.await();
}
@Test
public void queryExchangeRate_wasSuccessfulShouldRespondWithRateUSD()
throws InterruptedException, JSONException, TimeoutException {
final String base = "XMR";
final String quote = "USD"; final String quote = "USD";
final double rate = 100; final double rate = 1.56;
MockResponse jsonMockResponse = new MockResponse().setBody( MockResponse jsonMockResponse = new MockResponse().setBody(
createMockExchangeRateResponse(base, quote, rate)); createMockExchangeRateResponse(base, quote, rate));
mockWebServer.enqueue(jsonMockResponse); mockWebServer.enqueue(jsonMockResponse);
@ -121,6 +149,7 @@ public class ExchangeRateTest {
public void queryExchangeRate_wasNotSuccessfulShouldCallOnError() public void queryExchangeRate_wasNotSuccessfulShouldCallOnError()
throws InterruptedException, JSONException, TimeoutException { throws InterruptedException, JSONException, TimeoutException {
mockWebServer.enqueue(new MockResponse().setResponseCode(500)); mockWebServer.enqueue(new MockResponse().setResponseCode(500));
exchangeApi.queryExchangeRate("XMR", "USD", new ExchangeCallback() { exchangeApi.queryExchangeRate("XMR", "USD", new ExchangeCallback() {
@Override @Override
public void onSuccess(final ExchangeRate exchangeRate) { public void onSuccess(final ExchangeRate exchangeRate) {
@ -142,9 +171,10 @@ public class ExchangeRateTest {
@Test @Test
public void queryExchangeRate_unknownAssetShouldCallOnError() public void queryExchangeRate_unknownAssetShouldCallOnError()
throws InterruptedException, JSONException, TimeoutException { throws InterruptedException, JSONException, TimeoutException {
mockWebServer.enqueue(new MockResponse(). MockResponse jsonMockResponse = new MockResponse().setBody(
setResponseCode(200). createMockExchangeRateErrorResponse());
setBody("{\"error\":[\"EQuery:Unknown asset pair\"]}")); mockWebServer.enqueue(jsonMockResponse);
exchangeApi.queryExchangeRate("XMR", "ABC", new ExchangeCallback() { exchangeApi.queryExchangeRate("XMR", "ABC", new ExchangeCallback() {
@Override @Override
public void onSuccess(final ExchangeRate exchangeRate) { public void onSuccess(final ExchangeRate exchangeRate) {
@ -157,7 +187,7 @@ public class ExchangeRateTest {
waiter.assertTrue(e instanceof ExchangeException); waiter.assertTrue(e instanceof ExchangeException);
ExchangeException ex = (ExchangeException) e; ExchangeException ex = (ExchangeException) e;
waiter.assertTrue(ex.getCode() == 200); waiter.assertTrue(ex.getCode() == 200);
waiter.assertEquals(ex.getErrorMsg(), "EQuery:Unknown asset pair"); waiter.assertEquals(ex.getErrorMsg(), "id not found");
waiter.resume(); waiter.resume();
} }
@ -167,19 +197,49 @@ public class ExchangeRateTest {
private String createMockExchangeRateResponse(final String base, final String quote, final double rate) { private String createMockExchangeRateResponse(final String base, final String quote, final double rate) {
return "{\n" + return "{\n" +
" \"error\":[],\n" + " \"data\": {\n" +
" \"result\":{\n" + " \"id\": 328, \n" +
" \"X" + base + "Z" + quote + "\":{\n" + " \"name\": \"Monero\", \n" +
" \"a\":[\"" + rate + "\",\"322\",\"322.000\"],\n" + " \"symbol\": \"" + base + "\", \n" +
" \"b\":[\"" + rate + "\",\"76\",\"76.000\"],\n" + " \"website_slug\": \"monero\", \n" +
" \"c\":[\"" + rate + "\",\"2.90000000\"],\n" + " \"rank\": 12, \n" +
" \"v\":[\"4559.03962053\",\"5231.33235586\"],\n" + " \"circulating_supply\": 16112286.0, \n" +
" \"p\":[\"" + rate + "\",\"" + rate + "\"],\n" + " \"total_supply\": 16112286.0, \n" +
" \"t\":[801,1014],\n" + " \"max_supply\": null, \n" +
" \"l\":[\"" + (rate * 0.8) + "\",\"" + rate + "\"],\n" + " \"quotes\": {\n" +
" \"h\":[\"" + (rate * 1.2) + "\",\"" + rate + "\"],\n" + " \"USD\": {\n" +
" \"o\":\"" + rate + "\"\n" + " \"price\": " + rate + ", \n" +
" \"volume_24h\": 35763700.0, \n" +
" \"market_cap\": 2559791130.0, \n" +
" \"percent_change_1h\": -0.16, \n" +
" \"percent_change_24h\": -3.46, \n" +
" \"percent_change_7d\": 1.49\n" +
" }, \n" +
(!"USD".equals(quote) ? (
" \"" + quote + "\": {\n" +
" \"price\": " + rate + ", \n" +
" \"volume_24h\": 30377728.701265607, \n" +
" \"market_cap\": 2174289586.0, \n" +
" \"percent_change_1h\": -0.16, \n" +
" \"percent_change_24h\": -3.46, \n" +
" \"percent_change_7d\": 1.49\n" +
" }\n") : "") +
" }, \n" +
" \"last_updated\": 1528492746\n" +
" }, \n" +
" \"metadata\": {\n" +
" \"timestamp\": 1528492705, \n" +
" \"error\": null\n" +
" }\n" + " }\n" +
"}";
}
private String createMockExchangeRateErrorResponse() {
return "{\n" +
" \"data\": null, \n" +
" \"metadata\": {\n" +
" \"timestamp\": 1525137187, \n" +
" \"error\": \"id not found\"\n" +
" }\n" + " }\n" +
"}"; "}";
} }