From 7ea39ac3f24d07a72d7a4614da0be21320f11c0c Mon Sep 17 00:00:00 2001 From: joemarct Date: Fri, 22 Apr 2022 11:18:35 +0800 Subject: [PATCH 01/12] Bumped up version to v0.7.0 --- package-lock.json | 2 +- package.json | 2 +- src-bex/manifest.json | 2 +- src-capacitor/android/app/build.gradle | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index ef0a1ce38..feea8fa1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "paytaca", - "version": "0.6.1", + "version": "0.7.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 814acef10..f3c026633 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "paytaca", - "version": "0.6.1", + "version": "0.7.0", "description": "Secure and convenient Bitcoin Cash wallet app", "productName": "Paytaca", "author": "joemar@paytaca.com", diff --git a/src-bex/manifest.json b/src-bex/manifest.json index 9d0d08ad4..351b23b15 100644 --- a/src-bex/manifest.json +++ b/src-bex/manifest.json @@ -1,7 +1,7 @@ { "name": "Paytaca", "description": "Secure and convenient Bitcoin Cash wallet app", - "version": "0.6.1", + "version": "0.7.0", "manifest_version": 2, "icons": { "16": "icons/icon-16x16.png", diff --git a/src-capacitor/android/app/build.gradle b/src-capacitor/android/app/build.gradle index 8d67e74e9..a4f00ba44 100644 --- a/src-capacitor/android/app/build.gradle +++ b/src-capacitor/android/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "com.paytaca.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 30 - versionName "v0.6.1" + versionCode 31 + versionName "v0.7.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. From c0abdcf7e152441ad7342c0f69d29be7001199bc Mon Sep 17 00:00:00 2001 From: khirvy019 Date: Mon, 25 Apr 2022 14:33:19 +0800 Subject: [PATCH 02/12] add vuex module for managing market value of assets --- src/store/index.js | 2 + src/store/market/actions.js | 102 ++++++++++++++++++++++++++++++++++ src/store/market/getters.js | 18 ++++++ src/store/market/index.js | 12 ++++ src/store/market/mutations.js | 51 +++++++++++++++++ src/store/market/state.js | 14 +++++ 6 files changed, 199 insertions(+) create mode 100644 src/store/market/actions.js create mode 100644 src/store/market/getters.js create mode 100644 src/store/market/index.js create mode 100644 src/store/market/mutations.js create mode 100644 src/store/market/state.js diff --git a/src/store/index.js b/src/store/index.js index 8ecd0c445..3dc0256bc 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -3,6 +3,7 @@ import Vuex from 'vuex' import createPersistedState from 'vuex-persistedstate' import global from './global' +import market from './market' import assets from './assets' import sep20 from './sep20' @@ -23,6 +24,7 @@ export default function (/* { ssrContext } */) { modules: { global, assets, + market, sep20 }, diff --git a/src/store/market/actions.js b/src/store/market/actions.js new file mode 100644 index 000000000..e2eb049ff --- /dev/null +++ b/src/store/market/actions.js @@ -0,0 +1,102 @@ +import axios from 'axios' + +export function updateCoinsList(context, { force = true }) { + if (Array.isArray(context.state.coinsList) && context.state.coinsList.length && !force) + return { data: context.state.coinsList, _fromVuexStore: true } + + return axios + .get( + 'https://api.coingecko.com/api/v3/coins/list', + { params: { include_platform: true } }, + ) + .then(response => { + // console.log(response) + if (Array.isArray(response.data)) { + context.commit('updateCoinsList', response.data) + return response + } + return Promise.reject({ response }) + }) +} + +export async function updateSupportedCurrencies(context, { force = true }) { + if (Array.isArray(context.state.currencyOptions) && context.state.currencyOptions.length >= 1 && !force) return + + const { data:currencies } = await axios.get('https://api.coingecko.com/api/v3/simple/supported_vs_currencies') + // console.log(currencies) + context.commit('updateCurrencyOptions', currencies) +} + +/** + * @returns { + * mainchain: { asset: { id:String, symbol:String }, coin: { id:String } }[], + * smartchain: { asset: { id:String, symbol:String }, coin: { id:String } }[], + * } + */ +export function getAllAssetList(context) { + const mainchainAssets = context.rootGetters['assets/getAssets'] + const smartchainAssets = context.rootGetters['sep20/getAssets'] + // console.log(mainchainAssets) + // console.log(smartchainAssets) + + const mainchain = mainchainAssets.map(asset => { + const filteredSymbol = context.state.coinsList + .filter(coin => String(coin.symbol).toLowerCase() === String(asset.symbol).toLowerCase()) + const filteredPlatform = filteredSymbol + .filter(coin => !coin.platforms || Object.getOwnPropertyNames(coin.platforms).length <= 1) + const coin = filteredPlatform.length ? filteredPlatform[0] : filteredSymbol[0] + // console.log(asset.name, filteredSymbol, filteredPlatform) + return { asset, coin } + }) + + const smartchain = smartchainAssets.map(asset => { + const filteredSymbol = context.state.coinsList + .filter(coin => String(coin.symbol).toLowerCase() === String(asset.symbol).toLowerCase()) + const filteredPlatform = filteredSymbol + .filter(coin => coin.platforms && coin.platforms.smartbch) + + const coin = filteredPlatform.length ? filteredPlatform[0] : filteredSymbol[0] + // console.log(asset.name, filteredSymbol, filteredPlatform) + return { asset, coin } + }) + + return { mainchain, smartchain } +} + + +export async function updateAssetPrices(context, { clearExisting = false }) { + const assetList = await context.dispatch('getAllAssetList') + console.log(assetList) + const coinIds = [] + coinIds.push( + ...assetList.mainchain + .map(({ coin }) => coin.id) + .filter(Boolean) + .filter((e, i, s) => s.indexOf(e) === i), + ...assetList.smartchain + .map(({ coin }) => coin.id) + .filter(Boolean) + .filter((e, i, s) => s.indexOf(e) === i), + ) + + const { data: prices } = await axios.get( + 'https://api.coingecko.com/api/v3/simple/price', + { + params: { + ids: coinIds.join(','), + vs_currencies: context.state.selectedCurrency, + } + } + ) + + const newAssetPrices = [...assetList.mainchain, ...assetList.smartchain].map(({ asset, coin }) => { + return { + assetId: asset.id, + coinId: coin.id, + prices: prices[coin.id], + } + }) + + if (clearExisting) context.commit('clearAssetPrices') + context.commit('updateAssetPrices', newAssetPrices) +} diff --git a/src/store/market/getters.js b/src/store/market/getters.js new file mode 100644 index 000000000..f5a04c697 --- /dev/null +++ b/src/store/market/getters.js @@ -0,0 +1,18 @@ +export function coinsList(state) { + if (Array.isArray(state.coinsList)) return [] + return state.coinsList +} + +export function currencyOptions(state) { + if (!Array.isArray(state.currencyOptions)) return [] + return state.currencyOptions +} + +export function selectedCurrency(state) { + return state.selectedCurrency +} + +export function assetPrices(state) { + if (!Array.isArray(state.assetPrices)) return [] + return state.assetPrices +} diff --git a/src/store/market/index.js b/src/store/market/index.js new file mode 100644 index 000000000..b41a219b9 --- /dev/null +++ b/src/store/market/index.js @@ -0,0 +1,12 @@ +import state from './state' +import * as getters from './getters' +import * as mutations from './mutations' +import * as actions from './actions' + +export default { + namespaced: true, + state, + getters, + mutations, + actions +} diff --git a/src/store/market/mutations.js b/src/store/market/mutations.js new file mode 100644 index 000000000..bba1e9773 --- /dev/null +++ b/src/store/market/mutations.js @@ -0,0 +1,51 @@ +/** + * + * @param {Object} state vuex module state + * @param {{ id: String, name: String, symbol: String, platforms: Object }[]} coinsList + * @see {@link https://www.coingecko.com/en/api/documentation} + */ +export function updateCoinsList(state, coinsList) { + if (!Array.isArray(coinsList) || !coinsList.length) return + + state.coinsList = coinsList +} + +/** + * + * @param {Object} state vuex model state + * @param {String[]} currencyOptions + */ + export function updateCurrencyOptions(state, currencyOptions) { + if (!Array.isArray(currencyOptions) || !currencyOptions.length) return + state.currencyOptions = currencyOptions +} + +export function updateSelectedCurrency(state, currency) { + if (!Array.isArray(state.currencyOptions) || state.currencyOptions.indexOf(currency) < 0) return + + state.selectedCurrency = currency +} + +/** + * + * @param {Object} state vuex module state + * @param {{ assetId: String, prices: Map, coinId: String }[]} assetPrices + */ +export function updateAssetPrices(state, assetPrices) { + if (!Array.isArray(state.assetPrices)) state.assetPrices = [] + + assetPrices.forEach(assetPrice => { + let updated = false + for (var i=0; i < state.assetPrices.length; i++) { + if(state.assetPrices[i].assetId === assetPrice.assetId) { + updated = true + state.assetPrices[i] = assetPrice + } + } + if (!updated) state.assetPrices.push(assetPrice) + }) +} + +export function clearAssetPrices(state) { + state.assetPrices = [] +} diff --git a/src/store/market/state.js b/src/store/market/state.js new file mode 100644 index 000000000..d1a41c499 --- /dev/null +++ b/src/store/market/state.js @@ -0,0 +1,14 @@ +export default function () { + return { + coinsList: [], + currencyOptions: ['usd'], + selectedCurrency: 'usd', + assetPrices: [ + // { + // assetId: '', + // prices: { usd: 0.0 }, // map for currency and prices + // coinId: '', + // } + ], + } +} From ac0cddb264fbce9fa2f7be53c264cf70567312f9 Mon Sep 17 00:00:00 2001 From: khirvy019 Date: Mon, 25 Apr 2022 14:38:05 +0800 Subject: [PATCH 03/12] show balance of assets using selected currency --- src/App.vue | 6 ++++++ src/components/asset-cards.vue | 18 ++++++++++++++++++ src/pages/transaction/index.vue | 20 ++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/App.vue b/src/App.vue index b45ad25d4..af82319cc 100644 --- a/src/App.vue +++ b/src/App.vue @@ -38,6 +38,12 @@ export default { }) } }, + mounted () { + this.$store.dispatch('market/updateCoinsList', { force: false }) + .finally(() => { + this.$store.dispatch('market/updateAssetPrices', {}) + }) + }, created () { const vm = this setTimeout(function () { diff --git a/src/components/asset-cards.vue b/src/components/asset-cards.vue index 4d97d3b61..d815079c3 100644 --- a/src/components/asset-cards.vue +++ b/src/components/asset-cards.vue @@ -22,6 +22,9 @@ {{ asset.symbol }}

+
+ ~ {{ getAssetMarketBalance(asset) }} {{ String(selectedMarketCurrency).toUpperCase() }} +

@@ -55,9 +58,24 @@ export default { computed: { isSep20 () { return this.network === 'sBCH' + }, + selectedMarketCurrency() { + return this.$store.getters['market/selectedCurrency'] + }, + marketAssetPrices() { + return this.$store.getters['market/assetPrices'] } }, methods: { + getAssetMarketBalance(asset) { + if (!asset || !asset.id) return '' + + const assetPrice = this.marketAssetPrices.find(assetPrice => assetPrice.assetId === asset.id) + if (!assetPrice || !assetPrice.prices || !assetPrice.prices[this.selectedMarketCurrency]) return '' + const computedBalance = Number(asset.balance || 0) * Number(assetPrice.prices[this.selectedMarketCurrency]) + + return computedBalance.toFixed(2) + }, getFallbackAssetLogo(asset) { const logoGenerator = this.$store.getters['global/getDefaultAssetLogo'] return logoGenerator(String(asset && asset.id)) diff --git a/src/pages/transaction/index.vue b/src/pages/transaction/index.vue index 026c5fe5b..821a4bc08 100644 --- a/src/pages/transaction/index.vue +++ b/src/pages/transaction/index.vue @@ -36,6 +36,9 @@ {{ String(selectedAsset.balance).substring(0, 10) }}

+
+ ~ {{ selectedAssetMarketBalance }} {{ String(selectedMarketCurrency).toUpperCase() }} +

{{ today }}

@@ -212,7 +215,24 @@ export default { } }) }, + selectedAssetMarketPrice() { + if (!this.selectedAsset || !this.selectedAsset.id) return + return this.$store.getters['market/assetPrices'].find(assetPrice => assetPrice.assetId === this.selectedAsset.id) + }, + selectedMarketCurrency() { + return this.$store.getters['market/selectedCurrency'] + }, + selectedAssetMarketBalance () { + console.log(this.selectedAssetMarketPrice) + if (!this.selectedAsset) return '' + if (!this.selectedAssetMarketPrice) return '' + if (!this.selectedAssetMarketPrice.prices) return '' + if (!this.selectedAssetMarketPrice.prices[this.selectedMarketCurrency]) return '' + const computedBalance = Number(this.selectedAsset.balance || 0) * Number(this.selectedAssetMarketPrice.prices[this.selectedMarketCurrency]) + + return computedBalance.toFixed(2) + }, earliestBlock () { if (!Array.isArray(this.transactions) || !this.transactions.length) return 0 return Math.min( From ad4752a95abdd33a603781fe845e47415f805708 Mon Sep 17 00:00:00 2001 From: khirvy019 Date: Mon, 25 Apr 2022 15:14:19 +0800 Subject: [PATCH 04/12] add option to select currency to display in settings --- src/App.vue | 2 ++ src/pages/apps/settings.vue | 66 ++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/App.vue b/src/App.vue index af82319cc..d2cd23990 100644 --- a/src/App.vue +++ b/src/App.vue @@ -43,6 +43,8 @@ export default { .finally(() => { this.$store.dispatch('market/updateAssetPrices', {}) }) + + this.$store.dispatch('market/updateSupportedCurrencies', {}) }, created () { const vm = this diff --git a/src/pages/apps/settings.vue b/src/pages/apps/settings.vue index a630a1beb..9ef013814 100644 --- a/src/pages/apps/settings.vue +++ b/src/pages/apps/settings.vue @@ -33,6 +33,42 @@
+ +
+

WALLET

+ + + + Currency + + + + + + + + +
@@ -57,16 +93,44 @@ export default { securityOptionDialogStatus: 'dismiss', securityAuth: false, pinStatus: true, - darkMode: this.$q.dark.mode + darkMode: this.$q.dark.mode, + filteredCurrencyOptions: [], } }, components: { HeaderNav, pinDialog, securityOptionDialog }, watch: { darkMode (newVal, oldVal) { this.$q.dark.set(newVal) + }, + selectedCurrency() { + this.$store.dispatch('market/updateAssetPrices', {}) } }, + computed: { + currencyOptions () { + return this.$store.getters['market/currencyOptions'] + }, + selectedCurrency: { + get() { + return this.$store.getters['market/selectedCurrency'] + }, + set(value) { + this.$store.commit('market/updateSelectedCurrency', value) + } + }, + }, methods: { + filterCurrencyOptionSelection (val, update) { + if (!val) { + this.filteredCurrencyOptions = this.currencyOptions + } else { + const needle = String(val).toLowerCase() + this.filteredCurrencyOptions = this.currencyOptions + .filter(currency => String(currency).toLowerCase().indexOf(needle) >= 0) + } + + update() + }, popUpPinDialog () { this.pinDialogAction = 'SET NEW' }, From f1141511b82465356f81aefa6565eaae94888727 Mon Sep 17 00:00:00 2001 From: joemarct Date: Mon, 25 Apr 2022 18:34:14 +0800 Subject: [PATCH 05/12] Made minor display and placement changes --- src-capacitor/package.json | 2 +- src/components/asset-cards.vue | 10 +++++----- src/pages/transaction/index.vue | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src-capacitor/package.json b/src-capacitor/package.json index 911f55c66..91ddf298f 100644 --- a/src-capacitor/package.json +++ b/src-capacitor/package.json @@ -1,6 +1,6 @@ { "name": "paytaca", - "version": "0.6.1", + "version": "0.7.0", "description": "Secure and convenient Bitcoin Cash wallet app", "author": "joemar@paytaca.com", "private": true, diff --git a/src/components/asset-cards.vue b/src/components/asset-cards.vue index d815079c3..2ab02acc3 100644 --- a/src/components/asset-cards.vue +++ b/src/components/asset-cards.vue @@ -16,21 +16,21 @@ style="float: right; width: 20px; margin-top: -10px;"> -
+

{{ asset.symbol }}

-
- ~ {{ getAssetMarketBalance(asset) }} {{ String(selectedMarketCurrency).toUpperCase() }} -
-
+

{{ String(asset.balance).substring(0, 10) }}

+
+ {{ getAssetMarketBalance(asset) }} {{ String(selectedMarketCurrency).toUpperCase() }} +
diff --git a/src/pages/transaction/index.vue b/src/pages/transaction/index.vue index 821a4bc08..c323f0b1a 100644 --- a/src/pages/transaction/index.vue +++ b/src/pages/transaction/index.vue @@ -6,7 +6,7 @@
-
+