Browse Source

auto fetch balances

master
PhilReact 11 months ago
parent
commit
2480d56b4a
  1. 3
      core/language/us.json
  2. 3
      core/src/components/app-view.js
  3. 326
      core/src/components/controllers/coin-balances-controller.js
  4. 4
      core/src/components/friends-view/friends-view.js
  5. 6
      core/src/plugins/streams.js
  6. 9
      core/src/redux/app/actions/app-core.js
  7. 1
      core/src/redux/app/app-action-types.js
  8. 16
      core/src/redux/app/app-reducer.js
  9. 83
      plugins/plugins/core/trade-portal/trade-portal.src.js
  10. 43
      plugins/plugins/core/wallet/wallet-app.src.js

3
core/language/us.json

@ -398,7 +398,8 @@
"wchange56": "WARNING!",
"wchange57": "Memo",
"wchange58": "New Address",
"wchange59": "Coin"
"wchange59": "Coin",
"wchange60": "Reload txs"
},
"tradepage": {
"tchange1": "Trade Portal",

3
core/src/components/app-view.js

@ -46,6 +46,7 @@ import './notification-view/notification-bell-general.js'
import './friends-view/friends-side-panel-parent.js'
import './friends-view/save-settings-qdn.js'
import './friends-view/core-sync-status.js'
import './controllers/coin-balances-controller.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class AppView extends connect(store)(LitElement) {
@ -675,7 +676,7 @@ class AppView extends connect(store)(LitElement) {
</div>
</paper-dialog>
<div id="portal-target"></div>
<coin-balances-controller></coin-balances-controller>
`
}

326
core/src/components/controllers/coin-balances-controller.js

@ -0,0 +1,326 @@
import { LitElement, html, css } from 'lit';
import '@material/mwc-icon';
import { store } from '../../store';
import { connect } from 'pwa-helpers';
import '@vaadin/tooltip';
import { get } from 'lit-translate';
import { parentEpml } from '../show-plugin';
import { setCoinBalances } from '../../redux/app/app-actions';
class CoinBalancesController extends connect(store)(LitElement) {
static get properties() {
return {
coinList: { type: Object },
};
}
constructor() {
super();
this.coinList = {}
this.nodeUrl = this.getNodeUrl();
this.myNode = this.getMyNode();
this.fetchBalance = this.fetchBalance.bind(this)
this._updateCoinList = this._updateCoinList.bind(this)
this.stop = false
}
getNodeUrl() {
const myNode =
store.getState().app.nodeConfig.knownNodes[
store.getState().app.nodeConfig.node
];
const nodeUrl =
myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
return nodeUrl;
}
getMyNode() {
const myNode =
store.getState().app.nodeConfig.knownNodes[
store.getState().app.nodeConfig.node
];
return myNode;
}
async updateArrrWalletBalance() {
let _url = `/crosschain/arrr/walletbalance?apiKey=${this.myNode.apiKey}`
let _body = store.getState().app.selectedAddress.arrrWallet.seed58
await parentEpml.request('apiCall', {
url: _url,
method: 'POST',
body: _body,
}).then((res) => {
if (isNaN(Number(res))) {
//...
} else {
this.arrrWalletBalance = (Number(res) / 1e8).toFixed(8)
store.dispatch(
setCoinBalances({
type: 'arrr',
fullValue: Number(res)
})
);
}
}).catch(()=> {
console.log('error')
})
}
async updateQortWalletBalance() {
let qortAddress = store.getState().app.selectedAddress.address
await parentEpml.request('apiCall', {
url: `/addresses/balance/${qortAddress}?apiKey=${this.myNode.apiKey}`,
}).then((res) => {
this.qortWalletBalance = res
store.dispatch(
setCoinBalances({
type: 'qort',
fullValue: Number(res)
})
);
}).catch(()=> {
console.log('error')
})
}
async updateRvnWalletBalance() {
let _url = `/crosschain/rvn/walletbalance?apiKey=${this.myNode.apiKey}`
let _body = store.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
await parentEpml.request('apiCall', {
url: _url,
method: 'POST',
body: _body,
}).then((res) => {
if (isNaN(Number(res))) {
//...
} else {
this.rvnWalletBalance = (Number(res) / 1e8).toFixed(8)
store.dispatch(
setCoinBalances({
type: 'rvn',
fullValue: Number(res)
})
);
}
}).catch(()=> {
console.log('error')
})
}
async updateDgbWalletBalance() {
let _url = `/crosschain/dgb/walletbalance?apiKey=${this.myNode.apiKey}`
let _body = store.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
await parentEpml.request('apiCall', {
url: _url,
method: 'POST',
body: _body,
}).then((res) => {
if (isNaN(Number(res))) {
//...
} else {
this.dgbWalletBalance = (Number(res) / 1e8).toFixed(8)
store.dispatch(
setCoinBalances({
type: 'dgb',
fullValue: Number(res)
})
);
}
}).catch(()=> {
console.log('error')
})
}
async updateDogeWalletBalance() {
let _url = `/crosschain/doge/walletbalance?apiKey=${this.myNode.apiKey}`
let _body = store.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
await parentEpml.request('apiCall', {
url: _url,
method: 'POST',
body: _body,
}).then((res) => {
if (isNaN(Number(res))) {
//...
} else {
this.dogeWalletBalance = (Number(res) / 1e8).toFixed(8)
store.dispatch(
setCoinBalances({
type: 'doge',
fullValue: Number(res)
})
);
}
}).catch(()=> {
console.log('error')
})
}
async updateBtcWalletBalance() {
let _url = `/crosschain/btc/walletbalance?apiKey=${this.myNode.apiKey}`
let _body = store.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey
await parentEpml.request('apiCall', {
url: _url,
method: 'POST',
body: _body,
}).then((res) => {
if (isNaN(Number(res))) {
//...
} else {
this.btcWalletBalance = (Number(res) / 1e8).toFixed(8)
store.dispatch(
setCoinBalances({
type: 'btc',
fullValue: Number(res)
})
);
}
}).catch(()=> {
console.log('error')
})
}
async updateLtcWalletBalance() {
let _url = `/crosschain/ltc/walletbalance?apiKey=${this.myNode.apiKey}`
let _body = store.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
await parentEpml.request('apiCall', {
url: _url,
method: 'POST',
body: _body,
}).then((res) => {
if (isNaN(Number(res))) {
//...
} else {
this.ltcWalletBalance = (Number(res) / 1e8).toFixed(8)
store.dispatch(
setCoinBalances({
type: 'ltc',
fullValue: Number(res)
})
);
}
}).catch(()=> {
console.log('error')
})
}
_updateCoinList(event) {
const copyCoinList = {...this.coinList}
const coin = event.detail
if(!copyCoinList[coin]){
try {
if(coin === 'ltc'){
this.updateLtcWalletBalance()
} else if(coin === 'qort'){
this.updateQortWalletBalance()
} else if(coin === 'doge'){
this.updateDogeWalletBalance()
} else if(coin === 'btc'){
this.updateBtcWalletBalance()
} else if(coin === 'dgb'){
this.updateDgbWalletBalance()
} else if(coin === 'rvn'){
this.updateRvnWalletBalance()
}else if(coin === 'arrr'){
this.updateArrrWalletBalance()
}
} catch (error) {
}
}
copyCoinList[coin] = Date.now() + 120000;
this.coinList = copyCoinList
this.requestUpdate()
}
async fetchCoins(arrayOfCoins){
const getCoinBalances = (arrayOfCoins || []).map(
async (coin) => {
if(coin === 'ltc'){
await this.updateLtcWalletBalance()
} else if(coin === 'qort'){
this.updateQortWalletBalance()
} else if(coin === 'doge'){
this.updateDogeWalletBalance()
} else if(coin === 'btc'){
this.updateBtcWalletBalance()
} else if(coin === 'dgb'){
this.updateDgbWalletBalance()
} else if(coin === 'rvn'){
this.updateRvnWalletBalance()
}else if(coin === 'arrr'){
this.updateArrrWalletBalance()
}
})
await Promise.all(getCoinBalances);
}
async fetchBalance(){
try {
let arrayOfCoins = []
const copyObject = {...this.coinList}
const currentDate = Date.now()
const array = Object.keys(this.coinList)
for (const key of array) {
const item = this.coinList[key]
if(item < currentDate){
delete copyObject[key]
} else {
arrayOfCoins.push(key)
}
}
if(!this.stop){
this.stop = true
await this.fetchCoins(arrayOfCoins)
this.stop = false
}
this.coinList = copyObject
} catch (error) {
this.stop = false
}
}
connectedCallback() {
super.connectedCallback();
this.intervalID = setInterval(this.fetchBalance, 45000);
window.addEventListener(
'ping-coin-controller-with-coin',
this._updateCoinList
);
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener(
'ping-coin-controller-with-coin',
this._updateCoinList
);
if(this.intervalID){
clearInterval(this.intervalID);
}
}
render() {
return html``;
}
}
customElements.define('coin-balances-controller', CoinBalancesController);

4
core/src/components/friends-view/friends-view.js

@ -114,16 +114,13 @@ class FriendsView extends connect(store)(LitElement) {
this.friendList = detail
}
_updateFeed(event) {
console.log({event})
const detail = event.detail
console.log({detail})
this.mySelectedFeeds = detail
this.requestUpdate()
}
connectedCallback() {
super.connectedCallback()
console.log('callback')
window.addEventListener('friends-my-friend-list-event', this._updateFriends)
window.addEventListener('friends-my-selected-feeds-event', this._updateFeed)
}
@ -317,7 +314,6 @@ class FriendsView extends connect(store)(LitElement) {
}
render() {
console.log('rendered1')
return html`
<div class="container">
<div id="viewElement" class="container-body" style=${"position: relative"}>

6
core/src/plugins/streams.js

@ -9,6 +9,7 @@ const CHAT_HEADS_STREAM_NAME = 'chat_heads'
const NODE_CONFIG_STREAM_NAME = 'node_config'
const CHAT_LAST_SEEN = 'chat_last_seen'
const SIDE_EFFECT_ACTION = 'side_effect_action'
const COIN_BALANCES_ACTION = 'coin_balances'
export const loggedInStream = new EpmlStream(LOGIN_STREAM_NAME, () => store.getState().app.loggedIn)
export const configStream = new EpmlStream(CONFIG_STREAM_NAME, () => store.getState().config)
@ -18,6 +19,8 @@ export const chatHeadsStateStream = new EpmlStream(CHAT_HEADS_STREAM_NAME, () =>
export const nodeConfigStream = new EpmlStream(NODE_CONFIG_STREAM_NAME, () => store.getState().app.nodeConfig)
export const chatLastSeenStream = new EpmlStream(CHAT_LAST_SEEN, () => store.getState().app.chatLastSeen)
export const sideEffectActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => store.getState().app.sideEffectAction)
export const coinBalancesActionStream = new EpmlStream(COIN_BALANCES_ACTION, () => store.getState().app.coinBalances)
@ -62,6 +65,9 @@ store.subscribe(() => {
if (oldState.app.sideEffectAction !== state.app.sideEffectAction) {
sideEffectActionStream.emit(state.app.sideEffectAction)
}
if (oldState.app.coinBalances !== state.app.coinBalances) {
coinBalancesActionStream.emit(state.app.coinBalances)
}
oldState = state

9
core/src/redux/app/actions/app-core.js

@ -1,5 +1,5 @@
// Core App Actions here...
import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT } from '../app-action-types.js'
import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT, SET_COIN_BALANCES } from '../app-action-types.js'
export const doUpdateBlockInfo = (blockObj) => {
return (dispatch, getState) => {
@ -157,4 +157,11 @@ export const setSideEffectAction = (payload)=> {
type: SET_SIDE_EFFECT,
payload
}
}
export const setCoinBalances = (payload)=> {
return {
type: SET_COIN_BALANCES,
payload
}
}

1
core/src/redux/app/app-action-types.js

@ -33,3 +33,4 @@ export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
export const IS_OPEN_DEV_DIALOG = 'IS_OPEN_DEV_DIALOG'
export const SET_NEW_NOTIFICATION = 'SET_NEW_NOTIFICATION'
export const SET_SIDE_EFFECT= 'SET_SIDE_EFFECT'
export const SET_COIN_BALANCES= 'SET_COIN_BALANCES'

16
core/src/redux/app/app-reducer.js

@ -1,6 +1,6 @@
// Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage.
import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js'
import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, REMOVE_NODE, EDIT_NODE, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT } from './app-action-types.js'
import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, REMOVE_NODE, EDIT_NODE, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT, SET_COIN_BALANCES } from './app-action-types.js'
import { initWorkersReducer } from './reducers/init-workers.js'
import { loginReducer } from './reducers/login-reducer.js'
import { setNode, addNode, removeNode, editNode } from './reducers/manage-node.js'
@ -52,7 +52,8 @@ const INITIAL_STATE = {
tabInfo: {},
isOpenDevDialog: false,
newNotification: null,
sideEffectAction: null
sideEffectAction: null,
coinBalances: {}
}
export default (state = INITIAL_STATE, action) => {
@ -293,6 +294,17 @@ export default (state = INITIAL_STATE, action) => {
sideEffectAction: action.payload
}
}
case SET_COIN_BALANCES: {
const copyBalances = {...state.coinBalances}
copyBalances[action.payload.type] = {
value: action.payload.value,
fullValue: action.payload.fullValue
}
return {
...state,
coinBalances: copyBalances
}
}
default:
return state

83
plugins/plugins/core/trade-portal/trade-portal.src.js

@ -904,6 +904,7 @@ class TradePortal extends LitElement {
this.myTradeLockScreenPass = ''
this.myTradeLockScreenSet = ''
this.tradeHelperMessage = ''
this.pingCoinBalancesController = this.pingCoinBalancesController.bind(this)
}
historicTradesTemplate() {
@ -1416,6 +1417,52 @@ class TradePortal extends LitElement {
`
}
pingCoinBalancesController(){
if(!this.selectedCoin) return
let coin = ''
switch (this.selectedCoin) {
case 'BITCOIN':
coin ='btc'
break
case 'LITECOIN':
coin = 'ltc'
break
case 'DOGECOIN':
coin = 'doge'
break
case 'DIGIBYTE':
coin = 'dgb'
break
case 'RAVENCOIN':
coin = 'rnv'
break
case 'PIRATECHAIN':
coin = 'arrr'
break
default:
break
}
const customEvent = new CustomEvent('ping-coin-controller-with-coin', {
detail: coin
});
window.parent.dispatchEvent(customEvent);
}
connectedCallback() {
super.connectedCallback();
this.intervalID = setInterval(this.pingCoinBalancesController, 30000);
}
disconnectedCallback() {
super.disconnectedCallback();
if(this.intervalID){
clearInterval(this.intervalID);
}
}
firstUpdated() {
let _this = this
@ -1585,7 +1632,6 @@ class TradePortal extends LitElement {
this.dgbWallet = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.address
this.rvnWallet = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.address
this.arrrWallet = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.address
this.updateAccountBalance()
})
@ -1602,6 +1648,41 @@ class TradePortal extends LitElement {
}
this.config = JSON.parse(c)
})
parentEpml.subscribe('coin_balances', async (payload) => {
const coinBalances = JSON.parse(payload)
let coin = ''
switch (this.selectedCoin) {
case 'BITCOIN':
coin ='btc'
break
case 'LITECOIN':
coin = 'ltc'
break
case 'DOGECOIN':
coin = 'doge'
break
case 'DIGIBYTE':
coin = 'dgb'
break
case 'RAVENCOIN':
coin = 'rnv'
break
case 'PIRATECHAIN':
coin = 'arrr'
break
default:
break
}
if(coinBalances[coin]){
const res = coinBalances[coin].fullValue
let value = (Number(res) / 1e8).toFixed(8)
if(coin !== 'qort'){
value = (Number(res) / 1e8).toFixed(8)
}
this.listedCoins.get(this.selectedCoin).balance = value
this.requestUpdate()
}
})
let coinSelectionMenu = this.shadowRoot.getElementById("coinSelectionMenu")

43
plugins/plugins/core/wallet/wallet-app.src.js

@ -866,7 +866,22 @@ class MultiWallet extends LitElement {
this.wallets.get('rvn').wallet = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet
this.wallets.get('arrr').wallet = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet
})
parentEpml.subscribe('coin_balances', async (payload) => {
const coinBalances = JSON.parse(payload)
if(coinBalances[this._selectedWallet]){
const res = coinBalances[this._selectedWallet].fullValue
let value = Number(res).toFixed(8)
if(this._selectedWallet !== 'qort'){
value = (Number(res) / 1e8).toFixed(8)
}
this.wallets.get(this._selectedWallet).balance = value
this.balanceString = this.wallets.get(this._selectedWallet).balance + " " + this._selectedWallet.toLocaleUpperCase()
this.balance = this.wallets.get(this._selectedWallet).balance
}
})
})
this.pingCoinBalancesController = this.pingCoinBalancesController.bind(this)
}
render() {
@ -939,6 +954,9 @@ class MultiWallet extends LitElement {
<qortal-qrcode-generator data="${this.getSelectedWalletAddress()}" mode="octet" format="html" auto></qortal-qrcode-generator>
</div>
<div id="transactions">
<div style="display:flex;width:100%;justify-content:flex-end">
<vaadin-button theme="primary medium" style="width: auto;" @click=${() => this.fetchWalletDetails(this._selectedWallet)}><vaadin-icon icon="vaadin:refresh" slot="prefix"></vaadin-icon> ${translate("walletpage.wchange60")}</vaadin-button>
</div>
${this.loading ? html`<paper-spinner-lite style="display: block; margin: 5px auto;" active></paper-spinner-lite>` : ''}
<div id="transactionsDOM"></div>
</div>
@ -2821,6 +2839,7 @@ class MultiWallet extends LitElement {
}
firstUpdated() {
this.changeTheme()
this.changeLanguage()
this.paymentFee()
@ -2936,6 +2955,30 @@ class MultiWallet extends LitElement {
}
}
pingCoinBalancesController(){
if(!this._selectedWallet) return
const customEvent = new CustomEvent('ping-coin-controller-with-coin', {
detail: this._selectedWallet
});
window.parent.dispatchEvent(customEvent);
}
connectedCallback() {
super.connectedCallback();
this.intervalID = setInterval(this.pingCoinBalancesController, 30000);
}
disconnectedCallback() {
super.disconnectedCallback();
if(this.intervalID){
clearInterval(this.intervalID);
}
}
renderWalletLockButton() {
if (this.myWalletLockScreenPass === false && this.myWalletLockScreenSet === false) {
return html`

Loading…
Cancel
Save