From fce62bcd78ad7cd29280b3b50c8e0abe47ed70e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=ABck=20V=C3=A9zien?= Date: Tue, 23 Jan 2018 17:41:53 +0100 Subject: [PATCH 1/4] Add lastAddress and lastIndex --- package.json | 7 ++++- src/helpers/btc.js | 66 ++++++++++++++++++++++++++++++++++------------ yarn.lock | 58 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 108 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 9164b8ff..609812d2 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,11 @@ "storybook": "start-storybook -p 4444" }, "lint-staged": { - "*.js": ["eslint --fix", "prettier --write", "git add"] + "*.js": [ + "eslint --fix", + "prettier --write", + "git add" + ] }, "electronWebpack": { "renderer": { @@ -42,6 +46,7 @@ "axios": "^0.17.1", "bcryptjs": "^2.4.3", "bitcoinjs-lib": "^3.3.2", + "blockchain.info": "^2.11.0", "bs58check": "^2.1.1", "color": "^2.0.1", "downshift": "^1.25.0", diff --git a/src/helpers/btc.js b/src/helpers/btc.js index 642af206..c2c49137 100644 --- a/src/helpers/btc.js +++ b/src/helpers/btc.js @@ -1,9 +1,11 @@ // @flow -import axios from 'axios' +// import axios from 'axios' import bitcoin from 'bitcoinjs-lib' import { formatCurrencyUnit } from '@ledgerhq/common/lib/data/currency' +const blockexplorer = require('blockchain.info/blockexplorer').usingNetwork(3) + export function format(v: string | number, options: Object = { alwaysShowSign: true }) { return formatCurrencyUnit( { @@ -45,12 +47,13 @@ export function computeTransaction(addresses: Array<*>) { } } -export function getTransactions(addresses: Array) { - return axios.get( - `http://api.ledgerwallet.com/blockchain/v2/btc_testnet/addresses/${addresses.join( - ',', - )}/transactions?noToken=true`, - ) +export function getTransactions(addresses: Array) { + // return axios.get( + // `http://api.ledgerwallet.com/blockchain/v2/btc_testnet/addresses/${addresses.join( + // ',', + // )}/transactions?noToken=true`, + // ) + return blockexplorer.getMultiAddress(addresses) } export async function getAccount({ @@ -67,6 +70,7 @@ export async function getAccount({ const script = segwit ? parseInt(network.scriptHash, 10) : parseInt(network.pubKeyHash, 10) let transactions = [] + let lastAddress = null const pubKeyToSegwitAddress = (pubKey, scriptVersion) => { const script = [0x00, 0x14].concat(Array.from(bitcoin.crypto.hash160(pubKey))) @@ -82,26 +86,48 @@ export async function getAccount({ return pubKeyToSegwitAddress(hdnode.getPublicKeyBuffer(), script) } + const getAddress = ({ type, index }) => ({ + type, + index, + address: getPublicAddress({ + hdnode, + path: `${type === 'external' ? 0 : 1}/${index}`, + script, + segwit, + }), + }) + + const getLastAddress = (addresses, lastTx) => { + const address = addresses + .filter(a => a.type === 'external') + .find(a => a.address === lastTx.addr) || { index: 0 } + + return getAddress({ type: 'external', index: address.index + 1 }) + } + const nextPath = (index = 0) => { - const count = 20 - const getAddress = path => getPublicAddress({ hdnode, path, script, segwit }) + const gapLimit = 20 return Promise.all( - Array.from(Array(count).keys()).map(v => + Array.from(Array(gapLimit).keys()).map(v => Promise.all([ - getAddress(`0/${v + index}`), // external chain - getAddress(`1/${v + index}`), // internal chain + getAddress({ type: 'external', index: v + index }), + getAddress({ type: 'internal', index: v + index }), ]), ), ).then(async results => { - const currentAddresses = results.reduce((result, v) => [...result, ...v], []) + const addresses = results.reduce((result, v) => [...result, ...v], []) + const listAddresses = addresses.map(a => a.address) + + const { txs } = await getTransactions(listAddresses) - const { data: { txs } } = await getTransactions(currentAddresses) + const hasTransactions = txs.length > 0 - transactions = [...transactions, ...txs.map(computeTransaction(currentAddresses))] + transactions = [...transactions, ...txs.map(listAddresses)] + lastAddress = hasTransactions ? getLastAddress(addresses, txs[0].out[0]) : lastAddress - if (txs.length > 0) { - return nextPath(index + (count - 1)) + if (hasTransactions) { + return nextPath(index + (gapLimit - 1)) } return { @@ -110,6 +136,12 @@ export async function getAccount({ return result }, 0), transactions, + ...(lastAddress !== null + ? { + currentIndex: lastAddress.index, + address: lastAddress.address, + } + : {}), } }) } diff --git a/yarn.lock b/yarn.lock index 2f1d44f1..49b07487 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1776,12 +1776,28 @@ block-stream@*: dependencies: inherits "~2.0.0" +blockchain.info@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/blockchain.info/-/blockchain.info-2.11.0.tgz#63b46617e194164d377e183e6c667d3ef38ad5b6" + dependencies: + q "^1.4.1" + request-promise "^0.4.3" + url-join "0.0.1" + url-parse "^1.0.5" + url-pattern "^0.10.2" + optionalDependencies: + ws "^1.1.2" + bluebird-lst@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/bluebird-lst/-/bluebird-lst-1.0.5.tgz#bebc83026b7e92a72871a3dc599e219cbfb002a9" dependencies: bluebird "^3.5.1" +bluebird@^2.3: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + bluebird@^3.4.7, bluebird@^3.5.0, bluebird@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -2168,7 +2184,7 @@ chalk@0.5.1: strip-ansi "^0.3.0" supports-color "^0.2.0" -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -5621,7 +5637,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@^3.10.1: +lodash@^3.10.0, lodash@^3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -6322,6 +6338,10 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" +options@>=0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + ora@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" @@ -7091,7 +7111,7 @@ pushdata-bitcoin@^1.0.1: dependencies: bitcoin-ops "^1.3.0" -q@^1.1.2: +q@^1.1.2, q@^1.4.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -7718,6 +7738,15 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" +request-promise@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-0.4.3.tgz#3c8ddc82f06f8908d720aede1d6794258e22121c" + dependencies: + bluebird "^2.3" + chalk "^1.1.0" + lodash "^3.10.0" + request "^2.34" + request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -7745,7 +7774,7 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@^2.45.0, request@^2.81.0, request@^2.83.0: +request@^2.34, request@^2.45.0, request@^2.81.0, request@^2.83.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: @@ -8859,6 +8888,10 @@ uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +ultron@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -8956,6 +8989,10 @@ urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" +url-join@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-0.0.1.tgz#1db48ad422d3402469a87f7d97bdebfe4fb1e3c8" + url-loader@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.6.2.tgz#a007a7109620e9d988d14bce677a1decb9a993f7" @@ -8977,13 +9014,17 @@ url-parse@1.0.x: querystringify "0.0.x" requires-port "1.0.x" -url-parse@^1.1.8: +url-parse@^1.0.5, url-parse@^1.1.8: version "1.2.0" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" dependencies: querystringify "~1.0.0" requires-port "~1.0.0" +url-pattern@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/url-pattern/-/url-pattern-0.10.2.tgz#e9f07104982b72312db4473dd86a527b580015da" + url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" @@ -9307,6 +9348,13 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" +ws@^1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" From 6168ea729b37d79795cf04f9ce47e0ce611a785a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=ABck=20V=C3=A9zien?= Date: Tue, 23 Jan 2018 19:24:20 +0100 Subject: [PATCH 2/4] Store lastAdress and lastIndex for better sync --- src/actions/accounts.js | 5 +++- src/components/AccountPage.js | 2 +- src/components/modals/AddAccount.js | 7 ++---- src/helpers/btc.js | 36 ++++++++++++++++++---------- src/internals/accounts/sync.js | 4 ++-- src/internals/usb/wallet/accounts.js | 9 ++++--- src/reducers/accounts.js | 29 ++++++++++++++++------ src/renderer/events.js | 5 ++-- src/types/common.js | 2 ++ 9 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/actions/accounts.js b/src/actions/accounts.js index a0642bbb..bb4b20fd 100644 --- a/src/actions/accounts.js +++ b/src/actions/accounts.js @@ -20,7 +20,10 @@ export const fetchAccounts: FetchAccounts = () => ({ payload: db('accounts'), }) -const setAccountData = createAction('SET_ACCOUNT_DATA', (accountID, data) => ({ accountID, data })) +const setAccountData = createAction('DB:SET_ACCOUNT_DATA', (accountID, data) => ({ + accountID, + data, +})) export const syncAccount: Function = account => async (dispatch: Dispatch<*>) => { const { id, ...data } = account diff --git a/src/components/AccountPage.js b/src/components/AccountPage.js index bfcc454c..0d78e4bb 100644 --- a/src/components/AccountPage.js +++ b/src/components/AccountPage.js @@ -39,7 +39,7 @@ class AccountPage extends PureComponent { {format(accountData.balance)} - + {accountData.address} diff --git a/src/components/modals/AddAccount.js b/src/components/modals/AddAccount.js index 9e9ef74a..6639842b 100644 --- a/src/components/modals/AddAccount.js +++ b/src/components/modals/AddAccount.js @@ -219,16 +219,13 @@ class AddAccountModal extends PureComponent { const { inputValue, accounts } = this.state const { addAccount, closeModal } = this.props - const { id, balance, transactions } = accounts[index] + const { id, ...data } = accounts[index] addAccount({ id, name: inputValue.accountName, type: inputValue.wallet, - data: { - balance, - transactions, - }, + data, }) closeModal('add-account') diff --git a/src/helpers/btc.js b/src/helpers/btc.js index c2c49137..92802f1f 100644 --- a/src/helpers/btc.js +++ b/src/helpers/btc.js @@ -32,13 +32,26 @@ export const networks = [ ] export function computeTransaction(addresses: Array<*>) { + // return (transaction: Object) => { + // const outputVal = transaction.outputs + // .filter(o => addresses.includes(o.address)) + // .reduce((acc, cur) => acc + cur.value, 0) + // const inputVal = transaction.inputs + // .filter(i => addresses.includes(i.address)) + // .reduce((acc, cur) => acc + cur.value, 0) + // const balance = outputVal - inputVal + // return { + // ...transaction, + // balance, + // } + // } return (transaction: Object) => { - const outputVal = transaction.outputs - .filter(o => addresses.includes(o.address)) + const outputVal = transaction.out + .filter(o => addresses.includes(o.addr)) .reduce((acc, cur) => acc + cur.value, 0) const inputVal = transaction.inputs - .filter(i => addresses.includes(i.address)) - .reduce((acc, cur) => acc + cur.value, 0) + .filter(i => addresses.includes(i.prev_out.addr)) + .reduce((acc, cur) => acc + cur.prev_out.value, 0) const balance = outputVal - inputVal return { ...transaction, @@ -47,7 +60,7 @@ export function computeTransaction(addresses: Array<*>) { } } -export function getTransactions(addresses: Array) { +export function getTransactions(addresses: Array) { // return axios.get( // `http://api.ledgerwallet.com/blockchain/v2/btc_testnet/addresses/${addresses.join( // ',', @@ -67,6 +80,7 @@ export async function getAccount({ segwit: boolean, network: Object, }) { + const gapLimit = 20 const script = segwit ? parseInt(network.scriptHash, 10) : parseInt(network.pubKeyHash, 10) let transactions = [] @@ -105,11 +119,9 @@ export async function getAccount({ return getAddress({ type: 'external', index: address.index + 1 }) } - const nextPath = (index = 0) => { - const gapLimit = 20 - - return Promise.all( - Array.from(Array(gapLimit).keys()).map(v => + const nextPath = (index = 0) => + Promise.all( + Array.from(new Array(gapLimit).keys()).map(v => Promise.all([ getAddress({ type: 'external', index: v + index }), getAddress({ type: 'internal', index: v + index }), @@ -117,13 +129,14 @@ export async function getAccount({ ), ).then(async results => { const addresses = results.reduce((result, v) => [...result, ...v], []) + const listAddresses = addresses.map(a => a.address) const { txs } = await getTransactions(listAddresses) const hasTransactions = txs.length > 0 - transactions = [...transactions, ...txs.map(listAddresses)] + transactions = [...transactions, ...txs.map(computeTransaction(listAddresses))] lastAddress = hasTransactions ? getLastAddress(addresses, txs[0].out[0]) : lastAddress if (hasTransactions) { @@ -144,7 +157,6 @@ export async function getAccount({ : {}), } }) - } return nextPath(currentIndex) } diff --git a/src/internals/accounts/sync.js b/src/internals/accounts/sync.js index f5ccb044..c25f55fb 100644 --- a/src/internals/accounts/sync.js +++ b/src/internals/accounts/sync.js @@ -8,9 +8,9 @@ export default (send: Function) => ({ send('accounts.sync.progress', null, { kill: false }) - const syncAccount = ({ id }) => { + const syncAccount = ({ id, currentIndex }) => { const hdnode = getHDNode({ xpub58: id, network }) - return getAccount({ hdnode, network, segwit: true }).then(account => ({ + return getAccount({ currentIndex, hdnode, network, segwit: true }).then(account => ({ id, ...account, })) diff --git a/src/internals/usb/wallet/accounts.js b/src/internals/usb/wallet/accounts.js index c6202284..f7153446 100644 --- a/src/internals/usb/wallet/accounts.js +++ b/src/internals/usb/wallet/accounts.js @@ -113,21 +113,20 @@ export default async ({ } const hdnode = getHDNode({ xpub58, network }) - const { transactions, balance } = await getAccount({ hdnode, network, segwit }) + const account = await getAccount({ hdnode, network, segwit }) onProgress({ account: currentAccount, - transactions: transactions.length, + transactions: account.transactions.length, }) - const hasTransactions = transactions.length > 0 + const hasTransactions = account.transactions.length > 0 // If the first account is empty we still add it if (currentAccount === 0 || hasTransactions) { accounts[currentAccount] = { id: xpub58, - balance, - transactions, + ...account, } } diff --git a/src/reducers/accounts.js b/src/reducers/accounts.js index 17e2569c..1276bf34 100644 --- a/src/reducers/accounts.js +++ b/src/reducers/accounts.js @@ -22,13 +22,28 @@ const handlers: Object = { SET_ACCOUNT_DATA: ( state: AccountsState, { payload: { accountID, data } }: { payload: { accountID: string, data: AccountData } }, - ): AccountsState => ({ - ...state, - [accountID]: { - ...state[accountID], - data, - }, - }), + ): AccountsState => { + const account = state[accountID] + + const balance = get(account.data, 'balance', 0) + const transactions = get(account.data, 'transactions', []) + const currentIndex = data.currentIndex + ? data.currentIndex + : get(account.data, 'currentIndex', 0) + + account.data = { + ...account.data, + ...data, + balance: balance + data.balance, + currentIndex, + transactions: [...transactions, ...data.transactions], + } + + return { + ...state, + [accountID]: account, + } + }, } // Selectors diff --git a/src/renderer/events.js b/src/renderer/events.js index 231e6357..601eed81 100644 --- a/src/renderer/events.js +++ b/src/renderer/events.js @@ -14,7 +14,7 @@ type MsgPayload = { // wait a bit before launching update check const CHECK_UPDATE_TIMEOUT = 3e3 -const SYNC_ACCOUNT_TIMEOUT = 1e3 +const SYNC_ACCOUNT_TIMEOUT = 5e3 export function sendEvent(channel: string, msgType: string, data: any) { ipcRenderer.send(channel, { @@ -32,8 +32,9 @@ export function sendSyncEvent(channel: string, msgType: string, data: any): any function syncAccounts(accounts) { sendEvent('accounts', 'sync.all', { - accounts: Object.entries(accounts).map(([id]: [string, any]) => ({ + accounts: Object.entries(accounts).map(([id, account]: [string, any]) => ({ id, + currentIndex: account.data.currentIndex, })), }) } diff --git a/src/types/common.js b/src/types/common.js index d1fe6d13..7d8ea066 100644 --- a/src/types/common.js +++ b/src/types/common.js @@ -18,7 +18,9 @@ export type Transaction = { // -------------------- Accounts export type AccountData = { + address: string, balance: number, + currentIndex: number, transactions: Array, } From 6301346936df8c6a0e3519053667d3a016951da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=ABck=20V=C3=A9zien?= Date: Wed, 24 Jan 2018 09:25:43 +0100 Subject: [PATCH 3/4] Clean stuff --- src/components/AccountPage.js | 2 +- src/components/AppRegionDrag.js | 1 + src/components/base/Modal/index.js | 2 +- src/components/modals/AddAccount.js | 2 +- src/reducers/accounts.js | 11 +++++------ src/renderer/events.js | 11 ++++++----- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/components/AccountPage.js b/src/components/AccountPage.js index 0d78e4bb..53bcf968 100644 --- a/src/components/AccountPage.js +++ b/src/components/AccountPage.js @@ -43,7 +43,7 @@ class AccountPage extends PureComponent { - {accountData.transactions.map(tr => ( + {accountData.transactions.reverse().map(tr => ( {'-'} {format(tr.balance)} diff --git a/src/components/AppRegionDrag.js b/src/components/AppRegionDrag.js index bb22212f..9be9f09d 100644 --- a/src/components/AppRegionDrag.js +++ b/src/components/AppRegionDrag.js @@ -6,4 +6,5 @@ export default styled.div` -webkit-app-region: drag; background: ${p => p.theme.colors.white}; height: 40px; + z-index: 21; ` diff --git a/src/components/base/Modal/index.js b/src/components/base/Modal/index.js index 6f68c23e..a368900e 100644 --- a/src/components/base/Modal/index.js +++ b/src/components/base/Modal/index.js @@ -51,7 +51,7 @@ const Container = styled(Box).attrs({ })` overflow: hidden; position: fixed; - z-index: 1; + z-index: 20; ` const Backdrop = styled(Box).attrs({ diff --git a/src/components/modals/AddAccount.js b/src/components/modals/AddAccount.js index 6639842b..a4ffae17 100644 --- a/src/components/modals/AddAccount.js +++ b/src/components/modals/AddAccount.js @@ -133,7 +133,7 @@ class AddAccountModal extends PureComponent { componentWillReceiveProps(nextProps) { const { currentDevice } = nextProps - if (this.state.step !== 'createAccount') { + if (this.props.currentDevice === null && this.state.step !== 'createAccount') { this.setState({ step: currentDevice !== null ? 'startWallet' : 'connectDevice', }) diff --git a/src/reducers/accounts.js b/src/reducers/accounts.js index 1276bf34..8a44ec7b 100644 --- a/src/reducers/accounts.js +++ b/src/reducers/accounts.js @@ -24,15 +24,14 @@ const handlers: Object = { { payload: { accountID, data } }: { payload: { accountID: string, data: AccountData } }, ): AccountsState => { const account = state[accountID] + const { data: accountData } = account - const balance = get(account.data, 'balance', 0) - const transactions = get(account.data, 'transactions', []) - const currentIndex = data.currentIndex - ? data.currentIndex - : get(account.data, 'currentIndex', 0) + const balance = get(accountData, 'balance', 0) + const transactions = get(accountData, 'transactions', []) + const currentIndex = data.currentIndex ? data.currentIndex : get(accountData, 'currentIndex', 0) account.data = { - ...account.data, + ...accountData, ...data, balance: balance + data.balance, currentIndex, diff --git a/src/renderer/events.js b/src/renderer/events.js index 601eed81..8159b35f 100644 --- a/src/renderer/events.js +++ b/src/renderer/events.js @@ -6,6 +6,7 @@ import objectPath from 'object-path' import { updateDevices, addDevice, removeDevice } from 'actions/devices' import { syncAccount } from 'actions/accounts' import { setUpdateStatus } from 'reducers/update' +import { getAccounts } from 'reducers/accounts' type MsgPayload = { type: string, @@ -30,7 +31,9 @@ export function sendSyncEvent(channel: string, msgType: string, data: any): any }) } -function syncAccounts(accounts) { +function startSyncAccounts(store) { + const accounts = getAccounts(store.getState()) + sendEvent('accounts', 'sync.all', { accounts: Object.entries(accounts).map(([id, account]: [string, any]) => ({ id, @@ -45,7 +48,7 @@ export default (store: Object) => { sync: { success: accounts => { accounts.forEach(account => store.dispatch(syncAccount(account))) - setTimeout(() => syncAccounts(store.getState().accounts), SYNC_ACCOUNT_TIMEOUT) + setTimeout(() => startSyncAccounts(store), SYNC_ACCOUNT_TIMEOUT) }, }, }, @@ -77,8 +80,6 @@ export default (store: Object) => { handler(data) }) - const state = store.getState() - // First time, we get all devices sendEvent('usb', 'devices.all') @@ -86,7 +87,7 @@ export default (store: Object) => { sendEvent('usb', 'devices.listen') // Start accounts sync - syncAccounts(state.accounts) + startSyncAccounts(store) if (__PROD__) { // Start check of eventual updates From 1e944daeda9e190e42068d01942c5185bab426ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=ABck=20V=C3=A9zien?= Date: Wed, 24 Jan 2018 11:12:13 +0100 Subject: [PATCH 4/4] Reverse transactions in accounts reducers --- .prettierignore | 1 + src/components/AccountPage.js | 2 +- src/reducers/accounts.js | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..ec6d3cdd --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +package.json diff --git a/src/components/AccountPage.js b/src/components/AccountPage.js index 53bcf968..0d78e4bb 100644 --- a/src/components/AccountPage.js +++ b/src/components/AccountPage.js @@ -43,7 +43,7 @@ class AccountPage extends PureComponent { - {accountData.transactions.reverse().map(tr => ( + {accountData.transactions.map(tr => ( {'-'} {format(tr.balance)} diff --git a/src/reducers/accounts.js b/src/reducers/accounts.js index 8a44ec7b..5255d890 100644 --- a/src/reducers/accounts.js +++ b/src/reducers/accounts.js @@ -11,12 +11,20 @@ export type AccountsState = Accounts const state: AccountsState = {} +function setAccount(account: Account) { + return { + ...account, + data: { + ...account.data, + transactions: get(account.data, 'transactions', []).reverse(), + }, + } +} + const handlers: Object = { ADD_ACCOUNT: (state: AccountsState, { payload: account }: { payload: Account }) => ({ ...state, - [account.id]: { - ...account, - }, + [account.id]: setAccount(account), }), FETCH_ACCOUNTS: (state: AccountsState, { payload: accounts }: { payload: Accounts }) => accounts, SET_ACCOUNT_DATA: ( @@ -40,7 +48,7 @@ const handlers: Object = { return { ...state, - [accountID]: account, + [accountID]: setAccount(account), } }, }