From f8ee869a3dda95f718681d4908f4303be3f37160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Thu, 24 May 2018 18:36:40 +0200 Subject: [PATCH] introduce 'canBeSpent' --- src/bridge/EthereumJSBridge.js | 3 ++- src/bridge/EthereumMockJSBridge.js | 22 --------------------- src/bridge/LibcoreBridge.js | 6 ++++-- src/bridge/RippleJSBridge.js | 29 ++++++++++++++++++++++++++-- src/bridge/UnsupportedBridge.js | 2 ++ src/bridge/makeMockBridge.js | 3 +++ src/bridge/types.js | 2 ++ src/components/modals/Send/Footer.js | 16 +++++++++++---- 8 files changed, 52 insertions(+), 31 deletions(-) delete mode 100644 src/bridge/EthereumMockJSBridge.js diff --git a/src/bridge/EthereumJSBridge.js b/src/bridge/EthereumJSBridge.js index c77fdc4e..2639b376 100644 --- a/src/bridge/EthereumJSBridge.js +++ b/src/bridge/EthereumJSBridge.js @@ -305,8 +305,9 @@ const EthereumBridge: WalletBridge = { // $FlowFixMe EditFees, + // FIXME gasPrice calc is wrong... need to multiply with gasLimit I guess ? + canBeSpent: (a, t) => Promise.resolve(t.amount + t.gasPrice <= a.balance), getTotalSpent: (a, t) => Promise.resolve(t.amount + t.gasPrice), - getMaxAmount: (a, t) => Promise.resolve(a.balance - t.gasPrice), signAndBroadcast: async (a, t, deviceId) => { diff --git a/src/bridge/EthereumMockJSBridge.js b/src/bridge/EthereumMockJSBridge.js deleted file mode 100644 index bca51ca9..00000000 --- a/src/bridge/EthereumMockJSBridge.js +++ /dev/null @@ -1,22 +0,0 @@ -// @flow -import React from 'react' -import EthereumKind from 'components/FeesField/EthereumKind' -import type { EditProps } from './types' -import makeMockBridge from './makeMockBridge' - -const EditFees = ({ account, onChange, value }: EditProps<*>) => ( - { - onChange({ ...value, gasPrice }) - }} - gasPrice={value.gasPrice} - account={account} - /> -) - -export default makeMockBridge({ - extraInitialTransactionProps: () => ({ gasPrice: 0 }), - EditFees, - getTotalSpent: (a, t) => Promise.resolve(t.amount + t.gasPrice), - getMaxAmount: (a, t) => Promise.resolve(a.balance - t.gasPrice), -}) diff --git a/src/bridge/LibcoreBridge.js b/src/bridge/LibcoreBridge.js index 6c4f17d4..f95d8911 100644 --- a/src/bridge/LibcoreBridge.js +++ b/src/bridge/LibcoreBridge.js @@ -159,9 +159,11 @@ const LibcoreBridge: WalletBridge = { isValidTransaction: (a, t) => (t.amount > 0 && t.recipient && true) || false, - getTotalSpent: (a, t) => Promise.resolve(t.amount + t.feePerByte), + canBeSpent: (a, t) => Promise.resolve(t.amount <= a.balance), // FIXME - getMaxAmount: (a, t) => Promise.resolve(a.balance - t.feePerByte), + getTotalSpent: (a, t) => Promise.resolve(t.amount), // FIXME + + getMaxAmount: (a, _t) => Promise.resolve(a.balance), // FIXME signAndBroadcast: (account, transaction, deviceId) => { const rawAccount = encodeAccount(account) diff --git a/src/bridge/RippleJSBridge.js b/src/bridge/RippleJSBridge.js index 33a30c79..51c66b0d 100644 --- a/src/bridge/RippleJSBridge.js +++ b/src/bridge/RippleJSBridge.js @@ -2,6 +2,7 @@ import React from 'react' import bs58check from 'ripple-bs58check' import { computeBinaryTransactionHash } from 'ripple-hashes' +import throttle from 'lodash/throttle' import type { Account, Operation } from '@ledgerhq/live-common/lib/types' import { getDerivations } from 'helpers/derivations' import getAddress from 'commands/getAddress' @@ -148,6 +149,25 @@ const txToOperation = (account: Account) => ({ return op } +const getServerInfo = (perCurrencyId => currency => { + if (perCurrencyId[currency.id]) return perCurrencyId[currency.id]() + const f = throttle(async () => { + const api = apiForCurrency(currency) + try { + await api.connect() + const res = await api.getServerInfo() + return res + } catch (e) { + f.cancel() + throw e + } finally { + api.disconnect() + } + }, 60000) + perCurrencyId[currency.id] = f + return f() +})({}) + const RippleJSBridge: WalletBridge = { scanAccountsOnDevice(currency, deviceId, { next, complete, error }) { let finished = false @@ -159,7 +179,7 @@ const RippleJSBridge: WalletBridge = { const api = apiForCurrency(currency) try { await api.connect() - const serverInfo = await api.getServerInfo() + const serverInfo = await getServerInfo(currency) const ledgers = serverInfo.completeLedgers.split('-') const minLedgerVersion = Number(ledgers[0]) const maxLedgerVersion = Number(ledgers[1]) @@ -269,7 +289,7 @@ const RippleJSBridge: WalletBridge = { try { await api.connect() if (finished) return - const serverInfo = await api.getServerInfo() + const serverInfo = await getServerInfo(currency) if (finished) return const ledgers = serverInfo.completeLedgers.split('-') const minLedgerVersion = Number(ledgers[0]) @@ -371,6 +391,11 @@ const RippleJSBridge: WalletBridge = { isValidTransaction: (a, t) => (t.amount > 0 && t.recipient && true) || false, + canBeSpent: async (a, t) => { + const r = await getServerInfo(a.currency) + return t.amount + t.fee + parseAPIValue(r.validatedLedger.reserveBaseXRP) <= a.balance + }, + getTotalSpent: (a, t) => Promise.resolve(t.amount + t.fee), getMaxAmount: (a, t) => Promise.resolve(a.balance - t.fee), diff --git a/src/bridge/UnsupportedBridge.js b/src/bridge/UnsupportedBridge.js index 55261eb4..0a6b26b9 100644 --- a/src/bridge/UnsupportedBridge.js +++ b/src/bridge/UnsupportedBridge.js @@ -30,6 +30,8 @@ const UnsupportedBridge: WalletBridge<*> = { getTransactionRecipient: () => '', + canBeSpent: () => Promise.resolve(false), + getTotalSpent: () => Promise.resolve(0), getMaxAmount: () => Promise.resolve(0), diff --git a/src/bridge/makeMockBridge.js b/src/bridge/makeMockBridge.js index f41b6daf..80a3de90 100644 --- a/src/bridge/makeMockBridge.js +++ b/src/bridge/makeMockBridge.js @@ -30,6 +30,7 @@ function makeMockBridge(opts?: Opts): WalletBridge<*> { extraInitialTransactionProps, getTotalSpent, getMaxAmount, + canBeSpent, } = { ...defaultOpts, ...opts, @@ -143,6 +144,8 @@ function makeMockBridge(opts?: Opts): WalletBridge<*> { isValidTransaction: (a, t) => (t.amount > 0 && t.recipient && true) || false, + canBeSpent, + getTotalSpent, getMaxAmount, diff --git a/src/bridge/types.js b/src/bridge/types.js index c400fc8c..97a6f211 100644 --- a/src/bridge/types.js +++ b/src/bridge/types.js @@ -84,6 +84,8 @@ export interface WalletBridge { // render the whole advanced part of the form EditAdvancedOptions?: React$ComponentType>; + canBeSpent(account: Account, transaction: Transaction): Promise; + getTotalSpent(account: Account, transaction: Transaction): Promise; // NB this is not used yet but we'll use it when we have MAX diff --git a/src/components/modals/Send/Footer.js b/src/components/modals/Send/Footer.js index 5a5f6d6d..83d50081 100644 --- a/src/components/modals/Send/Footer.js +++ b/src/components/modals/Send/Footer.js @@ -32,9 +32,16 @@ const mapStateToProps = createStructuredSelector({ exchange: exchangeSettingsForAccountSelector, }) -class Footer extends PureComponent { +class Footer extends PureComponent< + Props, + { + totalSpent: number, + canBeSpent: boolean, + }, +> { state = { totalSpent: 0, + canBeSpent: true, } componentDidMount() { this.resync() @@ -54,12 +61,13 @@ class Footer extends PureComponent { async resync() { const { account, bridge, transaction } = this.props const totalSpent = await bridge.getTotalSpent(account, transaction) + const canBeSpent = await bridge.canBeSpent(account, transaction) if (this.unmount) return - this.setState({ totalSpent }) + this.setState({ totalSpent, canBeSpent }) } render() { const { exchange, account, t, onNext, canNext, showTotal } = this.props - const { totalSpent } = this.state + const { totalSpent, canBeSpent } = this.state return ( @@ -69,7 +77,7 @@ class Footer extends PureComponent { account.balance ? 'pearl' : 'dark'} + color={!canBeSpent ? 'pearl' : 'dark'} val={totalSpent} unit={account.unit} showCode