diff --git a/src/blockchains.d.ts b/src/blockchains.d.ts index 9cde950c..f135821b 100644 --- a/src/blockchains.d.ts +++ b/src/blockchains.d.ts @@ -13,6 +13,10 @@ declare module '@storage/blockchains' { scriptHash: string; wif: string; logo: string; + bip32: { + public: number; + private: number; + }; } type blockchains = Record; let blockchains: blockchains; diff --git a/src/components/SyncRequest/SyncRequest.tsx b/src/components/SyncRequest/SyncRequest.tsx index 85224ea3..a2073bb1 100644 --- a/src/components/SyncRequest/SyncRequest.tsx +++ b/src/components/SyncRequest/SyncRequest.tsx @@ -5,8 +5,12 @@ import { useTranslation } from 'react-i18next'; import { useTheme } from '../../hooks'; import Authentication from '../Authentication/Authentication'; +import { blockchains } from '@storage/blockchains'; + +import { cryptos } from '../../types'; + const SyncRequest = (props: { - chain: string; + chain: keyof cryptos; actionStatus: (status: boolean) => void; }) => { // so we need our xpubkey, then generate address and show user the address. If not the same, tell user to restore or create wallet from scratch. @@ -14,6 +18,8 @@ const SyncRequest = (props: { const { Fonts, Gutters, Layout, Colors, Common } = useTheme(); const [authenticationOpen, setAuthenticationOpen] = useState(false); + const blockchainConfig = blockchains[props.chain]; + const approve = () => { console.log('Approve'); props.actionStatus(true); @@ -60,7 +66,8 @@ const SyncRequest = (props: { ]} > {t('home:ssp_sync_request', { - chain: props.chain.toUpperCase(), + chain: blockchainConfig.name, + symbol: blockchainConfig.symbol, })} diff --git a/src/lib/wallet.ts b/src/lib/wallet.ts index 8f10f531..e5705f77 100644 --- a/src/lib/wallet.ts +++ b/src/lib/wallet.ts @@ -29,11 +29,13 @@ function generatexPubxPriv( coin: number, account = 0, type = 'p2sh', + chain: keyof cryptos, ): xPrivXpub { const scriptType = getScriptType(type); const seed = bip39.mnemonicToSeedSync(mnemonic); - const masterKey = HDKey.fromMasterSeed(seed); + const bipParams = blockchains[chain].bip32; + const masterKey = HDKey.fromMasterSeed(seed, bipParams); const externalChain = masterKey.derive( `m/${bip}'/${coin}'/${account}'/${scriptType}'`, ); @@ -52,8 +54,16 @@ export function getMasterXpub( coin: number, account = 0, type = 'p2sh', + chain: keyof cryptos, ): string { - const xPubxPriv = generatexPubxPriv(mnemonic, bip, coin, account, type); + const xPubxPriv = generatexPubxPriv( + mnemonic, + bip, + coin, + account, + type, + chain, + ); return xPubxPriv.xpub; } @@ -64,8 +74,16 @@ export function getMasterXpriv( coin: number, account = 0, type = 'p2sh', + chain: keyof cryptos, ): string { - const xPubxPriv = generatexPubxPriv(mnemonic, bip, coin, account, type); + const xPubxPriv = generatexPubxPriv( + mnemonic, + bip, + coin, + account, + type, + chain, + ); return xPubxPriv.xpriv; } @@ -77,8 +95,9 @@ export function generateMultisigAddress( addressIndex: number, chain: keyof cryptos, ): multisig { - const externalChain1 = HDKey.fromExtendedKey(xpub1); - const externalChain2 = HDKey.fromExtendedKey(xpub2); + const bipParams = blockchains[chain].bip32; + const externalChain1 = HDKey.fromExtendedKey(xpub1, bipParams); + const externalChain2 = HDKey.fromExtendedKey(xpub2, bipParams); const externalAddress1 = externalChain1 .deriveChild(typeIndex) @@ -128,7 +147,8 @@ export function generateAddressKeypair( chain: keyof cryptos, ): keyPair { const libID = getLibId(chain); - const externalChain = HDKey.fromExtendedKey(xpriv); + const bipParams = blockchains[chain].bip32; + const externalChain = HDKey.fromExtendedKey(xpriv, bipParams); const externalAddress = externalChain .deriveChild(typeIndex) @@ -157,7 +177,8 @@ export function generateIdentityAddress( const addressIndex = 0; // identity index const libID = getLibId(chain); - const externalChain = HDKey.fromExtendedKey(xpub); + const bipParams = blockchains[chain].bip32; + const externalChain = HDKey.fromExtendedKey(xpub, bipParams); const externalAddress = externalChain .deriveChild(typeIndex) diff --git a/src/screens/Create/Create.tsx b/src/screens/Create/Create.tsx index 1254916a..0313ad05 100644 --- a/src/screens/Create/Create.tsx +++ b/src/screens/Create/Create.tsx @@ -170,6 +170,7 @@ function Create({ navigation }: Props) { blockchainConfig.slip, 0, blockchainConfig.scriptType, + identityChain, ); // takes ~3 secs const xpub = getMasterXpub( mnemonicPhrase, @@ -177,6 +178,7 @@ function Create({ navigation }: Props) { blockchainConfig.slip, 0, blockchainConfig.scriptType, + identityChain, ); // takes ~3 secs const xprivBlob = CryptoJS.AES.encrypt( xpriv, diff --git a/src/screens/Home/Home.tsx b/src/screens/Home/Home.tsx index e116f2af..324f719e 100644 --- a/src/screens/Home/Home.tsx +++ b/src/screens/Home/Home.tsx @@ -67,6 +67,8 @@ type Props = { navigation: any; }; +const xpubRegex = /^([xyYzZtuUvV]pub[1-9A-HJ-NP-Za-km-z]{79,108})$/; + function Home({ navigation }: Props) { // focusability of inputs const alreadyMounted = useRef(false); // as of react strict mode, useEffect is triggered twice. This is a hack to prevent that without disabling strict mode @@ -97,8 +99,6 @@ function Home({ navigation }: Props) { const { newTx, clearTx } = useSocket(); - const blockchainConfig = blockchains[activeChain]; - useEffect(() => { if (alreadyMounted.current) { return; @@ -152,6 +152,9 @@ function Home({ navigation }: Props) { }; const checkXpubXpriv = async () => { + // todo loading animation on chain sync approval + const chainToUse = activeChain as keyof cryptos; + const blockchainConfigToUse = blockchains[chainToUse]; if (!xpubKey || !xprivKey) { // just a precaution to make sure xpub and xpriv are set. Should acutally never end up here getUniqueId() @@ -161,20 +164,22 @@ function Home({ navigation }: Props) { const pwForEncryption = id + password; const mmm = CryptoJS.AES.decrypt(seedPhrase, pwForEncryption); const mnemonicPhrase = mmm.toString(CryptoJS.enc.Utf8); - // generate master xpriv for flux + // generate master xpriv, xpub for chain const xpriv = getMasterXpriv( mnemonicPhrase, 48, - blockchainConfig.slip, + blockchainConfigToUse.slip, 0, - blockchainConfig.scriptType, + blockchainConfigToUse.scriptType, + chainToUse, ); // takes ~3 secs const xpub = getMasterXpub( mnemonicPhrase, 48, - blockchainConfig.slip, + blockchainConfigToUse.slip, 0, - blockchainConfig.scriptType, + blockchainConfigToUse.scriptType, + chainToUse, ); // takes ~3 secs const xprivBlob = CryptoJS.AES.encrypt( xpriv, @@ -184,8 +189,8 @@ function Home({ navigation }: Props) { xpub, pwForEncryption, ).toString(); - setXprivKey(activeChain, xprivBlob); - setXpubKey(activeChain, xpubBlob); + setXprivKey(chainToUse, xprivBlob); + setXpubKey(chainToUse, xpubBlob); }) .catch((error) => { console.log(error.message); @@ -504,7 +509,7 @@ function Home({ navigation }: Props) { // only data dataToProcess = splittedInput[0]; } - if (dataToProcess.startsWith('xpub')) { + if (xpubRegex.test(dataToProcess)) { // xpub const xpubw = dataToProcess; handleSyncRequest(xpubw, chain); @@ -568,7 +573,7 @@ function Home({ navigation }: Props) { dataToProcess = splittedInput[0]; } // check if input is xpub or transaction - if (dataToProcess.startsWith('xpub')) { + if (xpubRegex.test(dataToProcess)) { // xpub const xpubw = scannedData; handleSyncRequest(xpubw, chain); diff --git a/src/screens/Restore/Restore.tsx b/src/screens/Restore/Restore.tsx index 01e0fa91..946eb7e2 100644 --- a/src/screens/Restore/Restore.tsx +++ b/src/screens/Restore/Restore.tsx @@ -176,6 +176,7 @@ function Restore({ navigation }: Props) { blockchainConfig.slip, 0, blockchainConfig.scriptType, + identityChain, ); // takes ~3 secs const xpub = getMasterXpub( mnemonicPhrase, @@ -183,6 +184,7 @@ function Restore({ navigation }: Props) { blockchainConfig.slip, 0, blockchainConfig.scriptType, + identityChain, ); // takes ~3 secs const xprivBlob = CryptoJS.AES.encrypt( xpriv, diff --git a/src/storage/blockchains.ts b/src/storage/blockchains.ts index 476dc6dc..5cde7287 100644 --- a/src/storage/blockchains.ts +++ b/src/storage/blockchains.ts @@ -14,6 +14,10 @@ const flux = { scriptHash: '1cbd', wif: '80', logo: '/src/assets/flux.svg', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4, + }, }; const fluxTestnet = { @@ -30,6 +34,10 @@ const fluxTestnet = { scriptHash: '1cba', wif: 'ef', logo: '/src/assets/flux.svg', + bip32: { + public: 0x043587cf, + private: 0x04358394, + }, }; const rvn = { @@ -46,6 +54,10 @@ const rvn = { scriptHash: '7a', wif: '80', logo: '/src/assets/rvn.svg', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4, + }, }; export const blockchains = { diff --git a/src/translations/resources/en/home.json b/src/translations/resources/en/home.json index 72a56524..f8b737fb 100644 --- a/src/translations/resources/en/home.json +++ b/src/translations/resources/en/home.json @@ -39,7 +39,7 @@ "sync_qr_needed": "Please scan QR code to synchronise your SSP Key first.", "err_tx_decode": "Error decoding transaction. Rejected.", "sending_request": "Sending {{amount}} {{symbol}} to {{address}}", - "ssp_sync_request": "SSP Wallet would like to link and synchronise {{chain}} chain to your SSP Key.", + "ssp_sync_request": "SSP Wallet would like to link and synchronise {{chain}} ({{symbol}}) chain to your SSP Key.", "ssp_key_info": "SSP Key is a second authentication factor for your SSP Wallet.", "manual_input_info": "Input your transaction to sign or xpub of your wallet to sync.", "ssp_help_about": "Your Second Key Factor authentication for your SSP Wallet.",