diff --git a/package.json b/package.json index 4d1a1526..99ed7b33 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ } }, "dependencies": { + "@ledgerhq/errors": "^4.35.1", "@ledgerhq/hw-app-btc": "^4.34.0", "@ledgerhq/hw-app-eth": "^4.32.0", "@ledgerhq/hw-app-xrp": "^4.32.0", diff --git a/src/bridge/EthereumJSBridge.js b/src/bridge/EthereumJSBridge.js index 145d6524..f7948a46 100644 --- a/src/bridge/EthereumJSBridge.js +++ b/src/bridge/EthereumJSBridge.js @@ -129,7 +129,7 @@ function isRecipientValid(currency, recipient) { } // Returns a warning if we detect a non-eip address -function getRecipientWarning(currency, recipient) { +function getRecipientWarning(account, recipient) { if (!recipient.match(/^0x[0-9a-fA-F]{40}$/)) return null const slice = recipient.substr(2) const isFullUpper = slice === slice.toUpperCase() @@ -420,9 +420,9 @@ const EthereumBridge: WalletBridge = { pullMoreOperations: () => Promise.resolve(a => a), // NOT IMPLEMENTED - isRecipientValid: (currency, recipient) => Promise.resolve(isRecipientValid(currency, recipient)), - getRecipientWarning: (currency, recipient) => - Promise.resolve(getRecipientWarning(currency, recipient)), + isRecipientValid: (account, recipient) => Promise.resolve(isRecipientValid(account, recipient)), + getRecipientWarning: (account, recipient) => + Promise.resolve(getRecipientWarning(account, recipient)), createTransaction: () => ({ amount: BigNumber(0), diff --git a/src/bridge/LibcoreBridge.js b/src/bridge/LibcoreBridge.js index e9d2ce8b..e6fb6d40 100644 --- a/src/bridge/LibcoreBridge.js +++ b/src/bridge/LibcoreBridge.js @@ -60,15 +60,15 @@ const EditAdvancedOptions = ({ onChange, value }: EditProps) => ( const recipientValidLRU = LRU({ max: 100 }) -const isRecipientValid = (currency, recipient) => { - const key = `${currency.id}_${recipient}` +const isRecipientValid = (account, recipient) => { + const key = `${account.currency.id}_${recipient}` let promise = recipientValidLRU.get(key) if (promise) return promise if (!recipient) return Promise.resolve(false) promise = libcoreValidAddress .send({ address: recipient, - currencyId: currency.id, + currencyId: account.currency.id, }) .toPromise() recipientValidLRU.set(key, promise) @@ -83,7 +83,7 @@ const getFeesKey = (a, t) => }` const getFees = async (a, transaction) => { - const isValid = await isRecipientValid(a.currency, transaction.recipient) + const isValid = await isRecipientValid(a, transaction.recipient) if (!isValid) return null const key = getFeesKey(a, transaction) let promise = feesLRU.get(key) diff --git a/src/bridge/RippleJSBridge.js b/src/bridge/RippleJSBridge.js index 53b105b5..a6d16ef6 100644 --- a/src/bridge/RippleJSBridge.js +++ b/src/bridge/RippleJSBridge.js @@ -34,6 +34,7 @@ import { NotEnoughBalance, FeeNotLoaded, NotEnoughBalanceBecauseDestinationNotCreated, + InvalidAddressBecauseDestinationIsAlsoSource, } from '@ledgerhq/errors' import type { WalletBridge, EditProps } from './types' @@ -136,15 +137,23 @@ async function signAndBroadcast({ a, t, deviceId, isCancelled, onSigned, onOpera } } -function isRecipientValid(recipient) { +function isRecipientValid(account, recipient) { try { bs58check.decode(recipient) - return true + + return !(account && account.freshAddress === recipient) } catch (e) { return false } } +function getRecipientWarning(account, recipient) { + if (account.freshAddress === recipient) { + return new InvalidAddressBecauseDestinationIsAlsoSource() + } + return null +} + function mergeOps(existing: Operation[], newFetched: Operation[]) { const ids = existing.map(o => o.id) const all = existing.concat(newFetched.filter(o => !ids.includes(o.id))) @@ -270,7 +279,7 @@ const getServerInfo = (map => endpointConfig => { })({}) const recipientIsNew = async (endpointConfig, recipient) => { - if (!isRecipientValid(recipient)) return false + if (!isRecipientValid(null, recipient)) return false const api = apiForEndpointConfig(RippleAPI, endpointConfig) try { await api.connect() @@ -505,8 +514,9 @@ const RippleJSBridge: WalletBridge = { pullMoreOperations: () => Promise.resolve(a => a), // FIXME not implemented - isRecipientValid: (currency, recipient) => Promise.resolve(isRecipientValid(recipient)), - getRecipientWarning: () => Promise.resolve(null), + isRecipientValid: (account, recipient) => Promise.resolve(isRecipientValid(account, recipient)), + getRecipientWarning: (account, recipient) => + Promise.resolve(getRecipientWarning(account, recipient)), createTransaction: () => ({ amount: BigNumber(0), diff --git a/src/bridge/makeMockBridge.js b/src/bridge/makeMockBridge.js index 93080000..169bbd4d 100644 --- a/src/bridge/makeMockBridge.js +++ b/src/bridge/makeMockBridge.js @@ -128,7 +128,7 @@ function makeMockBridge(opts?: Opts): WalletBridge<*> { } }, - isRecipientValid: (currency, recipient) => Promise.resolve(recipient.length > 0), + isRecipientValid: (account, recipient) => Promise.resolve(recipient.length > 0), getRecipientWarning: () => Promise.resolve(null), createTransaction: () => ({ diff --git a/src/bridge/types.js b/src/bridge/types.js index eea8cefa..64835064 100644 --- a/src/bridge/types.js +++ b/src/bridge/types.js @@ -52,8 +52,8 @@ export interface WalletBridge { // count is user's desired number of ops to pull (but implementation can decide to ignore it or not) pullMoreOperations(initialAccount: Account, count: number): Promise<(Account) => Account>; - isRecipientValid(currency: Currency, recipient: string): Promise; - getRecipientWarning(currency: Currency, recipient: string): Promise; + isRecipientValid(account: Account, recipient: string): Promise; + getRecipientWarning(account: Account, recipient: string): Promise; // Related to send funds: diff --git a/src/components/modals/Send/fields/RecipientField.js b/src/components/modals/Send/fields/RecipientField.js index c2611d68..558061fb 100644 --- a/src/components/modals/Send/fields/RecipientField.js +++ b/src/components/modals/Send/fields/RecipientField.js @@ -53,8 +53,8 @@ class RecipientField extends Component< const { account, bridge, transaction } = this.props const syncId = ++this.syncId const recipient = bridge.getTransactionRecipient(account, transaction) - const isValid = await bridge.isRecipientValid(account.currency, recipient) - const warning = await bridge.getRecipientWarning(account.currency, recipient) + const isValid = await bridge.isRecipientValid(account, recipient) + const warning = await bridge.getRecipientWarning(account, recipient) if (syncId !== this.syncId) return if (this.isUnmounted) return this.setState({ isValid, warning }) @@ -69,9 +69,7 @@ class RecipientField extends Component< if (amount) { t = bridge.editTransactionAmount(account, t, amount) } - const warning = fromQRCode - ? await bridge.getRecipientWarning(account.currency, recipient) - : null + const warning = fromQRCode ? await bridge.getRecipientWarning(account, recipient) : null if (this.isUnmounted) return false if (warning) { // clear the input if field has warning AND has a warning @@ -97,7 +95,7 @@ class RecipientField extends Component< const error = !value || isValid ? QRCodeRefusedReason - : new InvalidAddress(null, { currencyName: account.currency.name }) + : warning || new InvalidAddress(null, { currencyName: account.currency.name }) return ( diff --git a/src/components/modals/Send/steps/01-step-amount.js b/src/components/modals/Send/steps/01-step-amount.js index dddbb3e3..fd810e9c 100644 --- a/src/components/modals/Send/steps/01-step-amount.js +++ b/src/components/modals/Send/steps/01-step-amount.js @@ -133,7 +133,7 @@ export class StepAmountFooter extends PureComponent< const totalSpent = await bridge.getTotalSpent(account, transaction) if (syncId !== this.syncId) return const isRecipientValid = await bridge.isRecipientValid( - account.currency, + account, bridge.getTransactionRecipient(account, transaction), ) if (syncId !== this.syncId) return diff --git a/static/i18n/en/app.json b/static/i18n/en/app.json index 5a77c007..16fd4a0f 100644 --- a/static/i18n/en/app.json +++ b/static/i18n/en/app.json @@ -900,6 +900,9 @@ "InvalidAddress": { "title": "This is not a valid {{currencyName}} address" }, + "InvalidAddressBecauseDestinationIsAlsoSource": { + "title": "Recipient address is the same as the sender address" + }, "CantOpenDevice": { "title": "Oops, couldn’t connect to device", "description": "Device detected but connection failed. Please try again or contact us if the problem persists." diff --git a/yarn.lock b/yarn.lock index 9a55d7e3..f93b69d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1677,10 +1677,10 @@ camelcase "^5.0.0" prettier "^1.13.7" -"@ledgerhq/errors@^4.32.0": - version "4.33.7" - resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-4.33.7.tgz#b78becd20e8a68f7115ad0986fa357a8adddf6b7" - integrity sha512-1vKWcttI5NHpT6rMKKuxWPAjfwDgfgUTf/AyNAT5KXHlhiLvqnA3NDCdNUVadajVNKSa/s1u1ZWKismtbfePzg== +"@ledgerhq/errors@^4.32.0", "@ledgerhq/errors@^4.35.1": + version "4.35.1" + resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-4.35.1.tgz#3f162dc05480e444083b6381bd098df187751633" + integrity sha512-2Bo3/NRKyz3ddR07TvZ87VpDJc8fz4+ONLJnhzC0mwIwu+Pxal6SgCBiGtv503oGxkgDuG5PtODZBaehWkGRnQ== "@ledgerhq/hw-app-btc@^4.32.0": version "4.32.0"