diff --git a/web/cashtab/src/hooks/useWallet.js b/web/cashtab/src/hooks/useWallet.js --- a/web/cashtab/src/hooks/useWallet.js +++ b/web/cashtab/src/hooks/useWallet.js @@ -19,6 +19,7 @@ isValidCashtabCache, isValidContactList, parseInvalidSettingsForMigration, + validateMnemonicWordList, } from 'utils/validation'; import localforage from 'localforage'; import { currency } from 'components/Common/Ticker'; @@ -906,6 +907,16 @@ try { mnemonicTestOutput = BCH.Mnemonic.validate(mnemonic, wordlist); + const localMnemonicTestOutput = validateMnemonicWordList( + mnemonic, + wordlist, + ); + + if (mnemonicTestOutput === localMnemonicTestOutput) { + console.log( + 'mnemonicTestOutput matches localMnemonicTestOutput', + ); + } if (mnemonicTestOutput === 'Valid mnemonic') { return true; diff --git a/web/cashtab/src/utils/__tests__/validation.test.js b/web/cashtab/src/utils/__tests__/validation.test.js --- a/web/cashtab/src/utils/__tests__/validation.test.js +++ b/web/cashtab/src/utils/__tests__/validation.test.js @@ -21,6 +21,7 @@ isValidContactList, parseInvalidSettingsForMigration, isValidCashtabCache, + validateMnemonicWordList, } from '../validation'; import { currency } from 'components/Common/Ticker.js'; import { fromSatoshisToXec } from 'utils/cashMethods'; @@ -48,8 +49,28 @@ cashtabCacheWithTokenNameNotString, cashtabCacheWithMissingTokenName, } from 'utils/__mocks__/mockCashtabCache'; +import * as bip39 from 'bip39'; describe('Validation utils', () => { + it(`validateMnemonicWordList() returns a success message for a valid mnemonic`, () => { + const validMnemonic = + 'labor tail bulb distance estate collect lecture into smile differ yard legal'; + expect( + validateMnemonicWordList(validMnemonic, bip39.wordlists.english), + ).toBe('Valid mnemonic'); + }); + it(`validateMnemonicWordList() returns an error message for an invalid mnemonic`, () => { + const validMnemonic = + 'labor tail bulb not valid collect lecture into smile differ yard legal'; + expect( + validateMnemonicWordList(validMnemonic, bip39.wordlists.english), + ).toBe('Invalid mnemonic'); + }); + it(`validateMnemonicWordList() returns an error message for an empty mnemonic`, () => { + expect(validateMnemonicWordList('', bip39.wordlists.english)).toBe( + 'Invalid mnemonic', + ); + }); it(`Returns 'false' if ${currency.ticker} send amount is a valid send amount`, () => { expect(shouldRejectAmountInput('10', currency.ticker, 20.0, 300)).toBe( false, diff --git a/web/cashtab/src/utils/validation.js b/web/cashtab/src/utils/validation.js --- a/web/cashtab/src/utils/validation.js +++ b/web/cashtab/src/utils/validation.js @@ -2,6 +2,21 @@ import { currency } from 'components/Common/Ticker.js'; import { fromSatoshisToXec } from 'utils/cashMethods'; import cashaddr from 'ecashaddrjs'; +import * as bip39 from 'bip39'; + +// reference: https://github.com/Permissionless-Software-Foundation/bch-js/blob/62e56c832b35731880fe448269818b853c76dd80/src/mnemonic.js#L160-L180 +export const validateMnemonicWordList = (mnemonic, wordlist) => { + // Preprocess the words + const words = mnemonic.split(' '); + // Detect blank phrase + if (words.length === 0) return 'Blank mnemonic'; + + // Check the words are valid + const isValid = bip39.validateMnemonic(mnemonic, wordlist); + if (!isValid) return 'Invalid mnemonic'; + + return 'Valid mnemonic'; +}; // Validate cash amount export const shouldRejectAmountInput = (