From c090f6c93cd209927ddb99e87d0ec2d079c51701 Mon Sep 17 00:00:00 2001 From: Elijah Lopez Date: Sat, 29 Apr 2023 19:21:19 -0400 Subject: [PATCH] Add more fiat currencies --- main.qml | 68 +++++++++++++++--------------- pages/settings/SettingsLayout.qml | 70 ++++++++++++++++++------------- 2 files changed, 75 insertions(+), 63 deletions(-) diff --git a/main.qml b/main.qml index 15bfa68473..255393ee1d 100644 --- a/main.qml +++ b/main.qml @@ -102,23 +102,24 @@ ApplicationWindow { // fiat price conversion property real fiatPrice: 0 - property var fiatPriceAPIs: { - return { - "kraken": { - "xmrusd": "https://api.kraken.com/0/public/Ticker?pair=XMRUSD", - "xmreur": "https://api.kraken.com/0/public/Ticker?pair=XMREUR" - }, - "coingecko": { - "xmrusd": "https://api.coingecko.com/api/v3/simple/price?ids=monero&vs_currencies=usd", - "xmreur": "https://api.coingecko.com/api/v3/simple/price?ids=monero&vs_currencies=eur" - }, - "cryptocompare": { - "xmrusd": "https://min-api.cryptocompare.com/data/price?fsym=XMR&tsyms=USD", - "xmreur": "https://min-api.cryptocompare.com/data/price?fsym=XMR&tsyms=EUR", - } - } - } + // {provider name: {ticker: price_api_url}} + // API response schema depends on the provider + property var fiatCurrencies: ["usd", "eur", "aed", "ars", "aud", "bdt", "bhd", "brl", "cad", "chf", "clp", "cny", "czk", "gbp", "hkd", + "huf", "idr", "ils", "inr", "jpy", "krw", "kwd", "lkr", "mmk", "mxn", "myr", "ngn", "nok", "nzd", "php", + "pkr", "pln", "rub", "sar", "sek", "sgd", "thb", "try", "twd", "uah", "vef", "vnd", "zar", "xau"]; + property var fiatPriceAPIs: fiatCurrencies.reduce(function(obj, x) { + const key = `xmr${x}`; // e.g. xmrusd + if (x === "usd" || x === "eur") { + // Kraken only supports XMRUSD and XMREUR + obj["kraken"][key] = `https://api.kraken.com/0/public/Ticker?pair=XMR${x}`; + } + obj["coingecko"][key] = `https://api.coingecko.com/api/v3/simple/price?ids=monero&vs_currencies=${x}`; + obj["cryptocompare"][key] = `https://min-api.cryptocompare.com/data/price?fsym=XMR&tsyms=${x}`; + return obj; + }, {"kraken": {}, "coingecko": {}, "cryptocompare": {}}) + // if the user is using Kraken, the following is used if the user wants non USD/EUR + property string fiatPriceBackupProvider: "coingecko" // true if wallet ever synchronized property bool walletInitialized : false @@ -137,7 +138,7 @@ ApplicationWindow { passwordDialog.onAcceptedCallback = function() { if(walletPassword === passwordDialog.password) passwordDialog.close(); - else + else passwordDialog.showError(qsTr("Wrong password") + translationManager.emptyString); } passwordDialog.open(usefulName(persistentSettings.wallet_path)); @@ -1029,11 +1030,9 @@ ApplicationWindow { var isReserveProof = signature.indexOf("ReserveProofV") === 0; if (address.length > 0 && !isReserveProof) { result = currentWallet.checkTxProof(txid, address, message, signature); - } - else if (isReserveProof) { + } else if (isReserveProof) { result = currentWallet.checkReserveProof(address, message, signature); - } - else { + } else { result = currentWallet.checkSpendProof(txid, message, signature); } var results = result.split("|"); @@ -1065,7 +1064,7 @@ ApplicationWindow { informationPopup.title = qsTr("Payment proof check") + translationManager.emptyString; informationPopup.icon = good ? StandardIcon.Information : StandardIcon.Critical; informationPopup.text = good ? qsTr("Good signature") : qsTr("Bad signature"); - } + } else if (isReserveProof && results[0] === "true") { var good = results[1] === "true"; informationPopup.title = qsTr("Reserve proof check") + translationManager.emptyString; @@ -1152,19 +1151,21 @@ ApplicationWindow { appWindow.fiatApiError("Kraken API has error(s)"); return; } - - var key = currency === "xmreur" ? "XXMRZEUR" : "XXMRZUSD"; + // i.e. xmr[a-z]+ -> XXMRZ[A-Z]+ + var key = `XXMRZ${currency.substring(3).toUpperCase()}`; var ticker = resp.result[key]["c"][0]; return ticker; } else if(url.startsWith("https://api.coingecko.com/api/v3/")){ - var key = currency === "xmreur" ? "eur" : "usd"; + // i.e. xmr[a-z]+ -> [a-z]+ + var key = currency.substring(3); if(!resp.hasOwnProperty("monero") || !resp["monero"].hasOwnProperty(key)){ appWindow.fiatApiError("Coingecko API has error(s)"); return; } return resp["monero"][key]; } else if(url.startsWith("https://min-api.cryptocompare.com/data/")){ - var key = currency === "xmreur" ? "EUR" : "USD"; + // i.e. xmr[a-z]+ -> [A-Z]+ + var key = currency.substring(3).toUpperCase(); if(!resp.hasOwnProperty(key)){ appWindow.fiatApiError("cryptocompare API has error(s)"); return; @@ -1235,7 +1236,7 @@ ApplicationWindow { var provider = appWindow.fiatPriceAPIs[userProvider]; var userCurrency = persistentSettings.fiatPriceCurrency; if(!provider.hasOwnProperty(userCurrency)){ - appWindow.fiatApiError("currency \"" + userCurrency + "\" not implemented"); + appWindow.fiatApiError("currency \"" + userCurrency + "\"is not supported by provider \"" + userProvider + "\""); } var url = provider[userCurrency]; @@ -1243,15 +1244,12 @@ ApplicationWindow { } function fiatApiCurrencySymbol() { - switch (persistentSettings.fiatPriceCurrency) { - case "xmrusd": - return "USD"; - case "xmreur": - return "EUR"; - default: - console.error("unsupported currency", persistentSettings.fiatPriceCurrency); - return "UNSUPPORTED"; + let currency = persistentSettings.fiatPriceCurrency.substring(3); + if (fiatCurrencies.indexOf(currency) !== -1) { + return currency.toUpperCase(); } + console.error("unsupported currency", persistentSettings.fiatPriceCurrency); + return "UNSUPPORTED"; } function fiatApiConvertToFiat(amount) { diff --git a/pages/settings/SettingsLayout.qml b/pages/settings/SettingsLayout.qml index 38ce823ea8..8357d2df7a 100644 --- a/pages/settings/SettingsLayout.qml +++ b/pages/settings/SettingsLayout.qml @@ -1,21 +1,21 @@ // Copyright (c) 2014-2018, The Monero Project -// +// // All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. -// +// // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. -// +// // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL @@ -91,7 +91,7 @@ Rectangle { MoneroComponents.Style.blackTheme = !MoneroComponents.Style.blackTheme; } } - + MoneroComponents.CheckBox { checked: persistentSettings.askPasswordBeforeSending text: qsTr("Ask for password before sending a transaction") + translationManager.emptyString @@ -190,9 +190,21 @@ Rectangle { labelFontSize: 14 dataModel: fiatPriceProvidersModel onChanged: { - var obj = dataModel.get(currentIndex); - persistentSettings.fiatPriceProvider = obj.data; - + var newProvider = dataModel.get(currentIndex).data; + var providerCurrencies = appWindow.fiatPriceAPIs[newProvider]; + // ONLY when the user changes the provider should the currency list also update + // This way, since Kraken is the default, users can see ALL supported currencies + fiatPriceCurrencyModel.clear(); + appWindow.fiatCurrencies.forEach(el => { + if (`xmr${el}` in providerCurrencies) fiatPriceCurrencyModel.append({ data: `xmr${el}`, column1: el.toUpperCase()}) + }); + // if fiatPriceCurrency is not supported by the new provider, use first available currency + if (!(persistentSettings.fiatPriceCurrency in providerCurrencies)) { + persistentSettings.fiatPriceCurrency = Object.keys(providerCurrencies)[0]; + fiatPriceCurrencyDropdown.currentIndex = 0; + } + persistentSettings.fiatPriceProvider = newProvider; + // refresh price after validating that the fiat currency is provided by the provider if(persistentSettings.fiatPriceEnabled) appWindow.fiatApiRefresh(); } @@ -203,12 +215,18 @@ Rectangle { Layout.maximumWidth: 100 labelText: qsTr("Currency") + translationManager.emptyString labelFontSize: 14 - currentIndex: persistentSettings.fiatPriceCurrency === "xmrusd" ? 0 : 1 + currentIndex: appWindow.fiatCurrencies.indexOf(persistentSettings.fiatPriceCurrency.substring(3)) dataModel: fiatPriceCurrencyModel onChanged: { - var obj = dataModel.get(currentIndex); - persistentSettings.fiatPriceCurrency = obj.data; - + var newCurrency = dataModel.get(currentIndex).data; + if (!(newCurrency in appWindow.fiatPriceAPIs[persistentSettings.fiatPriceProvider])) { + // this occurs if a fiat currency other than EUR/USD is selected and provider is Kraken + // so use appWindow.fiatPriceBackupProvider instead + let backupIdx = Object.keys(appWindow.fiatPriceAPIs).indexOf(appWindow.fiatPriceBackupProvider); + fiatPriceProviderDropDown.currentIndex = backupIdx; + persistentSettings.fiatPriceProvider = appWindow.fiatPriceBackupProvider; + } + persistentSettings.fiatPriceCurrency = newCurrency; if(persistentSettings.fiatPriceEnabled) appWindow.fiatApiRefresh(); } @@ -290,29 +308,26 @@ Rectangle { ListModel { id: fiatPriceCurrencyModel - ListElement { - data: "xmrusd" - column1: "USD" - } - ListElement { - data: "xmreur" - column1: "EUR" + Component.onCompleted: { + // populate with fiat currencies + appWindow.fiatCurrencies.forEach(el => { + fiatPriceCurrencyModel.append({ data: `xmr${el}`, column1: el.toUpperCase()}); + }); } } Component.onCompleted: { - // Dynamically fill fiatPrice dropdown based on `appWindow.fiatPriceAPIs` + // Dynamically fill fiatPrice dropdowns based on `appWindow.fiatPriceAPIs` var apis = appWindow.fiatPriceAPIs; fiatPriceProvidersModel.clear(); - var i = 0; - for (var api in apis){ - if (!apis.hasOwnProperty(api)) + for (var apiProvider in apis){ + if (!apis.hasOwnProperty(apiProvider)) continue; - fiatPriceProvidersModel.append({"column1": Utils.capitalize(api), "data": api}); + fiatPriceProvidersModel.append({data: apiProvider, column1: Utils.capitalize(apiProvider)}); - if(api === persistentSettings.fiatPriceProvider) + if(apiProvider === persistentSettings.fiatPriceProvider) fiatPriceProviderDropDown.currentIndex = i; i += 1; } @@ -320,4 +335,3 @@ Rectangle { console.log('SettingsLayout loaded'); } } -