diff --git a/src/bridge/EthereumJSBridge.js b/src/bridge/EthereumJSBridge.js index e68f70d2..2a48e6cf 100644 --- a/src/bridge/EthereumJSBridge.js +++ b/src/bridge/EthereumJSBridge.js @@ -420,15 +420,13 @@ const EthereumBridge: WalletBridge = { getTransactionRecipient: (a, t) => t.recipient, - isValidTransaction: (a, t) => (!t.amount.isZero() && t.recipient && true) || false, - EditFees, EditAdvancedOptions, - checkCanBeSpent: (a, t) => + checkValidTransaction: (a, t) => t.amount.isLessThanOrEqualTo(a.balance) - ? Promise.resolve() + ? Promise.resolve(true) : Promise.reject(new NotEnoughBalance()), getTotalSpent: (a, t) => diff --git a/src/bridge/LibcoreBridge.js b/src/bridge/LibcoreBridge.js index 642788d1..4f5d51eb 100644 --- a/src/bridge/LibcoreBridge.js +++ b/src/bridge/LibcoreBridge.js @@ -95,11 +95,11 @@ const getFees = async (a, transaction) => { return promise } -const checkCanBeSpent = (a, t) => +const checkValidTransaction = (a, t) => !t.amount - ? Promise.resolve() + ? Promise.resolve(true) : getFees(a, t) - .then(() => {}) + .then(() => true) .catch(e => { if (e.code === NOT_ENOUGH_FUNDS) { throw new NotEnoughBalance() @@ -192,9 +192,7 @@ const LibcoreBridge: WalletBridge = { // EditAdvancedOptions, - isValidTransaction: (a, t) => (!t.amount.isZero() && t.recipient && true) || false, - - checkCanBeSpent, + checkValidTransaction, getTotalSpent: (a, t) => t.amount.isZero() diff --git a/src/bridge/RippleJSBridge.js b/src/bridge/RippleJSBridge.js index f872eeb6..e3531790 100644 --- a/src/bridge/RippleJSBridge.js +++ b/src/bridge/RippleJSBridge.js @@ -474,9 +474,7 @@ const RippleJSBridge: WalletBridge = { getTransactionRecipient: (a, t) => t.recipient, - isValidTransaction: (a, t) => (!t.amount.isZero() && t.recipient && true) || false, - - checkCanBeSpent: async (a, t) => { + checkValidTransaction: async (a, t) => { const r = await getServerInfo(a.endpointConfig) if ( t.amount @@ -484,7 +482,7 @@ const RippleJSBridge: WalletBridge = { .plus(parseAPIValue(r.validatedLedger.reserveBaseXRP)) .isLessThanOrEqualTo(a.balance) ) { - return + return true } throw new NotEnoughBalance() }, diff --git a/src/bridge/UnsupportedBridge.js b/src/bridge/UnsupportedBridge.js index 6f5d5c12..ebc768e5 100644 --- a/src/bridge/UnsupportedBridge.js +++ b/src/bridge/UnsupportedBridge.js @@ -27,13 +27,11 @@ const UnsupportedBridge: WalletBridge<*> = { getTransactionAmount: () => BigNumber(0), - isValidTransaction: () => false, - editTransactionRecipient: () => null, getTransactionRecipient: () => '', - checkCanBeSpent: () => Promise.resolve(), + checkValidTransaction: () => Promise.resolve(false), getTotalSpent: () => Promise.resolve(BigNumber(0)), diff --git a/src/bridge/makeMockBridge.js b/src/bridge/makeMockBridge.js index 909dfe91..d266c234 100644 --- a/src/bridge/makeMockBridge.js +++ b/src/bridge/makeMockBridge.js @@ -18,7 +18,7 @@ const defaultOpts = { scanAccountDeviceSuccessRate: 0.8, transactionsSizeTarget: 100, extraInitialTransactionProps: () => null, - checkCanBeSpent: () => Promise.resolve(), + checkValidTransaction: () => Promise.resolve(), getTotalSpent: (a, t) => Promise.resolve(t.amount), getMaxAmount: a => Promise.resolve(a.balance), } @@ -36,7 +36,7 @@ function makeMockBridge(opts?: Opts): WalletBridge<*> { extraInitialTransactionProps, getTotalSpent, getMaxAmount, - checkCanBeSpent, + checkValidTransaction, } = { ...defaultOpts, ...opts, @@ -155,9 +155,7 @@ function makeMockBridge(opts?: Opts): WalletBridge<*> { EditAdvancedOptions, - isValidTransaction: (a, t) => (t.amount > 0 && t.recipient && true) || false, - - checkCanBeSpent, + checkValidTransaction, getTotalSpent, diff --git a/src/bridge/types.js b/src/bridge/types.js index 53a28250..eea8cefa 100644 --- a/src/bridge/types.js +++ b/src/bridge/types.js @@ -76,15 +76,16 @@ export interface WalletBridge { getTransactionRecipient(account: Account, transaction: Transaction): string; - isValidTransaction(account: Account, transaction: Transaction): boolean; - // render the whole Fees section of the form EditFees?: *; // React$ComponentType>; // render the whole advanced part of the form EditAdvancedOptions?: *; // React$ComponentType>; - checkCanBeSpent(account: Account, transaction: Transaction): Promise; + // validate the transaction and all currency specific validations here, we can return false + // to disable the button without throwing an error if we are handling the error on a different + // input or throw an error that will highlight the issue on the amount field + checkValidTransaction(account: Account, transaction: Transaction): Promise; getTotalSpent(account: Account, transaction: Transaction): Promise; diff --git a/src/components/RequestAmount/index.js b/src/components/RequestAmount/index.js index 63528897..2e9c1778 100644 --- a/src/components/RequestAmount/index.js +++ b/src/components/RequestAmount/index.js @@ -48,7 +48,7 @@ type OwnProps = { // left value (always the one which is returned) value: BigNumber, - canBeSpentError: ?Error, + validTransactionError: ?Error, // max left value max: BigNumber, @@ -113,7 +113,7 @@ const mapStateToProps = (state: State, props: OwnProps) => { export class RequestAmount extends PureComponent { static defaultProps = { max: BigNumber(Infinity), - canBeSpent: true, + validTransaction: true, withMax: true, } @@ -139,14 +139,14 @@ export class RequestAmount extends PureComponent { renderInputs(containerProps: Object) { // TODO move this inlined into render() for less spaghetti - const { value, account, rightCurrency, getCounterValue, canBeSpentError } = this.props + const { value, account, rightCurrency, getCounterValue, validTransactionError } = this.props const right = getCounterValue(value) || BigNumber(0) const rightUnit = rightCurrency.units[0] // FIXME: no way InputCurrency pure can work here. inlined InputRight (should be static func?), inline containerProps object.. return ( { +class AmountField extends Component<*, { validTransactionError: ?Error }> { state = { - canBeSpentError: null, + validTransactionError: null, } componentDidMount() { this.resync() @@ -27,11 +27,11 @@ class AmountField extends Component<*, { canBeSpentError: ?Error }> { const { account, bridge, transaction } = this.props const syncId = ++this.syncId try { - await bridge.checkCanBeSpent(account, transaction) + await bridge.checkValidTransaction(account, transaction) if (this.syncId !== syncId) return - this.setState({ canBeSpentError: null }) - } catch (canBeSpentError) { - this.setState({ canBeSpentError }) + this.setState({ validTransactionError: null }) + } catch (validTransactionError) { + this.setState({ validTransactionError }) } } @@ -42,14 +42,14 @@ class AmountField extends Component<*, { canBeSpentError: ?Error }> { render() { const { bridge, account, transaction, t } = this.props - const { canBeSpentError } = this.state + const { validTransactionError } = this.state return ( diff --git a/src/components/modals/Send/steps/01-step-amount.js b/src/components/modals/Send/steps/01-step-amount.js index 959cd92e..a38f3db7 100644 --- a/src/components/modals/Send/steps/01-step-amount.js +++ b/src/components/modals/Send/steps/01-step-amount.js @@ -134,11 +134,13 @@ export class StepAmountFooter extends PureComponent< bridge.getTransactionRecipient(account, transaction), ) if (syncId !== this.syncId) return - const canBeSpent = await bridge - .checkCanBeSpent(account, transaction) - .then(() => true, () => false) + const isValidTransaction = await bridge + .checkValidTransaction(account, transaction) + .then(result => result, () => false) + if (syncId !== this.syncId) return - const canNext = isRecipientValid && canBeSpent && totalSpent.gt(0) + const canNext = + !transaction.amount.isZero() && isRecipientValid && isValidTransaction && totalSpent.gt(0) this.setState({ totalSpent, canNext, isSyncing: false }) } catch (err) { logger.critical(err)