diff --git a/__tests__/addaccount.test.js b/__tests__/addaccount.test.js
index 30ebc406384..6da47912883 100644
--- a/__tests__/addaccount.test.js
+++ b/__tests__/addaccount.test.js
@@ -1,4 +1,4 @@
-import { getByText } from '@testing-library/testcafe';
+import { getAllByText, getByText } from '@testing-library/testcafe';
import AddAccountPage from './addaccount-page.po';
import DashboardPage from './dashboard-page.po';
@@ -42,3 +42,13 @@ test('Should be able to add a web3 address', async () => {
await dashboardPage.expectAddressToBePresent(FIXTURE_WEB3_ADDRESS);
await dashboardPage.expectAccountTableToMatchCount(1);
});
+
+test('Should be able to redirect to the correct flow from wallet id', async (t) => {
+ await addAccountPage.navigateTo(`${PAGES.ADD_ACCOUNT}/portis`);
+ await addAccountPage.waitForPage(PAGES.ADD_ACCOUNT_VIEWONLY);
+
+ await addAccountPage.selectEthereumNetwork();
+
+ const title = getAllByText('Portis');
+ await t.expect(title.exists).ok();
+});
diff --git a/__tests__/fixtures.js b/__tests__/fixtures.js
index 07144b40e31..6c1c0edc159 100644
--- a/__tests__/fixtures.js
+++ b/__tests__/fixtures.js
@@ -33,7 +33,8 @@ const PAGES = {
SWAP: `${FIXTURES_CONST.BASE_URL}/swap`,
BUY_MEMBERSHIP: `${FIXTURES_CONST.BASE_URL}/membership/buy`,
INTERACT_WITH_CONTRACTS: `${FIXTURES_CONST.BASE_URL}/interact-with-contracts`,
- DEPLOY_CONTRACTS: `${FIXTURES_CONST.BASE_URL}/deploy-contracts`
+ DEPLOY_CONTRACTS: `${FIXTURES_CONST.BASE_URL}/deploy-contracts`,
+ ONBOARDING: `${FIXTURES_CONST.BASE_URL}/onboarding`
};
const FIXTURE_ETHEREUM = 'Ethereum';
diff --git a/__tests__/onboarding-page.po.js b/__tests__/onboarding-page.po.js
new file mode 100644
index 00000000000..558c6ff495a
--- /dev/null
+++ b/__tests__/onboarding-page.po.js
@@ -0,0 +1,12 @@
+import BasePage from './base-page.po';
+import { PAGES } from './fixtures';
+
+export default class OnboardingPage extends BasePage {
+ async navigateToPage(wallet) {
+ this.navigateTo(`${PAGES.ONBOARDING}/${wallet}`);
+ }
+
+ async waitPageLoaded(wallet, timeToWait) {
+ await this.waitForPage(`${PAGES.ONBOARDING}/${wallet}`, timeToWait);
+ }
+}
diff --git a/__tests__/onboarding.test.js b/__tests__/onboarding.test.js
new file mode 100644
index 00000000000..6bc219b6197
--- /dev/null
+++ b/__tests__/onboarding.test.js
@@ -0,0 +1,24 @@
+import { getAllByText } from '@testing-library/testcafe';
+
+import { PAGES } from './fixtures';
+import OnboardingPage from './onboarding-page.po';
+
+const onboardingPage = new OnboardingPage();
+
+fixture('Onboarding').page(PAGES.ONBOARDING);
+
+test('Should be able to show a custodial exchange onboarding', async (t) => {
+ await onboardingPage.navigateToPage('kraken');
+ await onboardingPage.waitPageLoaded('kraken');
+
+ const title = getAllByText('Kraken');
+ await t.expect(title.exists).ok();
+});
+
+test('Should be able to show a non-custodial exchange onboarding', async (t) => {
+ await onboardingPage.navigateToPage('jaxx');
+ await onboardingPage.waitPageLoaded('jaxx');
+
+ const title = getAllByText('Jaxx');
+ await t.expect(title.exists).ok();
+});
diff --git a/package.json b/package.json
index 5ca7c9cbf14..71d161387ac 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"@mycrypto/eth-scan": "3.4.4",
"@mycrypto/ui": "0.24.1",
"@mycrypto/unlock-scan": "1.2.0",
+ "@mycrypto/wallet-list": "1.3.0",
"@mycrypto/wallets": "1.3.4",
"@reduxjs/toolkit": "1.6.0",
"@styled-system/should-forward-prop": "5.1.5",
@@ -267,4 +268,4 @@
"pre-push": "yarn test"
}
}
-}
\ No newline at end of file
+}
diff --git a/src/assets/icons/desktopTag.svg b/src/assets/icons/desktopTag.svg
new file mode 100755
index 00000000000..5c0ede52096
--- /dev/null
+++ b/src/assets/icons/desktopTag.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/exchangeTag.svg b/src/assets/icons/exchangeTag.svg
new file mode 100755
index 00000000000..012cff775ea
--- /dev/null
+++ b/src/assets/icons/exchangeTag.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/hardwareTag.svg b/src/assets/icons/hardwareTag.svg
new file mode 100755
index 00000000000..0515c38e649
--- /dev/null
+++ b/src/assets/icons/hardwareTag.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/mobileTag.svg b/src/assets/icons/mobileTag.svg
new file mode 100755
index 00000000000..5543c5aaf20
--- /dev/null
+++ b/src/assets/icons/mobileTag.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/icons/otherTag.svg b/src/assets/icons/otherTag.svg
new file mode 100755
index 00000000000..5be8d6410ec
--- /dev/null
+++ b/src/assets/icons/otherTag.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/assets/icons/walletconnectTag.svg b/src/assets/icons/walletconnectTag.svg
new file mode 100755
index 00000000000..b1aa625eb6c
--- /dev/null
+++ b/src/assets/icons/walletconnectTag.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/assets/icons/webTag.svg b/src/assets/icons/webTag.svg
new file mode 100755
index 00000000000..4541dbf1a63
--- /dev/null
+++ b/src/assets/icons/webTag.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/wallet-connect.png b/src/assets/images/wallet-connect.png
new file mode 100755
index 00000000000..6a64cf80a82
Binary files /dev/null and b/src/assets/images/wallet-connect.png differ
diff --git a/src/components/Icon/Icon.test.tsx b/src/components/Icon/Icon.test.tsx
index d3b0b222c2f..ce2098a4207 100644
--- a/src/components/Icon/Icon.test.tsx
+++ b/src/components/Icon/Icon.test.tsx
@@ -16,6 +16,10 @@ describe('Icon', () => {
const { container } = renderComponent({ type: 'add' });
expect(container.querySelector('img')).toBeInTheDocument();
});
+ it('renders a SVG Icon with a fill and a stroke', () => {
+ const { container } = renderComponent({ type: 'other-tag' });
+ expect(container.querySelector('svg')).toBeInTheDocument();
+ });
it('renders a PNG Icon by type', () => {
const { container } = renderComponent({ type: 'uni-logo' });
expect(container.querySelector('img')).toBeInTheDocument();
diff --git a/src/components/Icon/Icon.tsx b/src/components/Icon/Icon.tsx
index f3127d720ae..dcfcb610857 100644
--- a/src/components/Icon/Icon.tsx
+++ b/src/components/Icon/Icon.tsx
@@ -32,7 +32,11 @@ import remove from '@assets/icons/actions/remove.svg';
import logoMyCryptoTextBlue from '@assets/icons/brand/logo-text-blue.svg';
import logoMyCryptoText from '@assets/icons/brand/logo-text.svg';
import logoMyCrypto from '@assets/icons/brand/logo.svg';
+import desktopTag from '@assets/icons/desktopTag.svg';
+import exchangeTag from '@assets/icons/exchangeTag.svg';
import feedback from '@assets/icons/feedback.svg';
+import hardwareTag from '@assets/icons/hardwareTag.svg';
+import mobileTag from '@assets/icons/mobileTag.svg';
import navAddAccount from '@assets/icons/navigation/add-account.svg';
import navAssets from '@assets/icons/navigation/assets.svg';
import navBitcoin from '@assets/icons/navigation/bitcoin.svg';
@@ -84,6 +88,7 @@ import navTxStatus from '@assets/icons/navigation/tx-status.svg';
import navUnstoppable from '@assets/icons/navigation/unstoppable.svg';
import navVerifyMessage from '@assets/icons/navigation/verify-message.svg';
import newsletter from '@assets/icons/newsletter.svg';
+import otherTag from '@assets/icons/otherTag.svg';
import coinmarketcap from '@assets/icons/social/coinmarketcap.svg';
import facebook from '@assets/icons/social/facebook.svg';
import github from '@assets/icons/social/github.svg';
@@ -93,7 +98,9 @@ import telegram from '@assets/icons/social/telegram.svg';
import twitter from '@assets/icons/social/twitter.svg';
import telegramIcon from '@assets/icons/telegram.svg';
import twitterIcon from '@assets/icons/twitter.svg';
+import walletconnectTag from '@assets/icons/walletconnectTag.svg';
import website from '@assets/icons/website.svg';
+import webTag from '@assets/icons/webTag.svg';
import whitepaper from '@assets/icons/whitepaper.svg';
import antLogo from '@assets/images/ant-logo.png';
import arrowRight from '@assets/images/arrow-right.svg';
@@ -136,6 +143,7 @@ import membership from '@assets/images/membership/membership-none.svg';
import nodeLogo from '@assets/images/node-logo.svg';
import repLogo from '@assets/images/rep-logo.svg';
import uniLogo from '@assets/images/uni-logo.png';
+import walletConnectLogo from '@assets/images/wallet-connect.png';
import ledgerIcon from '@assets/images/wallets/ledger.svg';
import trezorIcon from '@assets/images/wallets/trezor.svg';
@@ -225,6 +233,15 @@ const svgIcons = {
'tx-receive': receiveIcon,
'tx-network': networkIcon,
+ /* Wallet Tags */
+ 'desktop-tag': desktopTag,
+ 'exchange-tag': exchangeTag,
+ 'hardware-tag': hardwareTag,
+ 'mobile-tag': mobileTag,
+ 'other-tag': otherTag,
+ 'walletconnect-tag': walletconnectTag,
+ 'web-tag': webTag,
+
/* Navigation */
'nav-home': navHome,
'nav-send': navSend,
@@ -284,7 +301,8 @@ const pngIcons = {
'lend-logo': lendLogo,
'ant-logo': antLogo,
'gol-logo': golemLogo,
- 'node-logo': nodeLogo
+ 'node-logo': nodeLogo,
+ 'wallet-connect': walletConnectLogo
};
type SvgIcons = keyof typeof svgIcons;
@@ -322,6 +340,16 @@ const SStrokeIcon = styled(SInlineSVG)`
stroke: ${({ color }) => color && color};
`;
+const SStrokeFillIcon = styled(SInlineSVG)`
+ &&&& {
+ fill: ${({ color, theme }) => (color ? theme.colors[color] : color)};
+ }
+ &&&&:hover {
+ fill: ${({ color, theme }) => (color ? theme.colors[color] : color)};
+ }
+ stroke: ${({ color, theme }) => (color ? theme.colors[color] : color)};
+`;
+
const SExpandableIcon = styled(SInlineSVG)`
cursor: pointer;
transition: all 0.3s ease-out;
@@ -366,8 +394,15 @@ export const isPNGType = (type: TIcon): type is PngIcons =>
export const getSVGIcon = (type: SvgIcons) => svgIcons[type];
const Icon = ({ type, color, ...props }: Props) => {
- if (type === 'website' || type === 'faucet-icon' || type === 'nav-nft') {
+ if (
+ type === 'website' ||
+ type === 'faucet-icon' ||
+ type === 'nav-nft' ||
+ type === 'walletconnect-tag'
+ ) {
return ;
+ } else if (type === 'other-tag') {
+ return ;
} else if (type === 'expandable') {
return ;
} else if (type === 'sort') {
diff --git a/src/components/WalletIcon.test.tsx b/src/components/WalletIcon.test.tsx
new file mode 100644
index 00000000000..09bf44046fb
--- /dev/null
+++ b/src/components/WalletIcon.test.tsx
@@ -0,0 +1,29 @@
+import { IWallet, wallets } from '@mycrypto/wallet-list';
+import { simpleRender } from 'test-utils';
+
+import { TIcon } from './Icon';
+import { WalletIcon } from './WalletIcon';
+
+const renderComponent = ({ wallet, interfaceIcon }: { wallet: IWallet; interfaceIcon?: TIcon }) => {
+ return simpleRender();
+};
+
+describe('WalletIcon', () => {
+ it('can render a WalletIcon', () => {
+ const wallet = wallets[0];
+ const props = { wallet: wallet };
+ const { getByText, container } = renderComponent(props);
+
+ expect(getByText(wallet.name, { exact: false })).toBeInTheDocument();
+ expect(container.querySelector('img')).toBeInTheDocument();
+ });
+
+ it('can render a WalletIcon with an interface icon', () => {
+ const wallet = wallets[0];
+ const props = { wallet: wallet, interfaceIcon: 'wallet-connect' as TIcon };
+ const { getByText, container } = renderComponent(props);
+
+ expect(getByText(wallet.name, { exact: false })).toBeInTheDocument();
+ expect(container.querySelector('div[data-testid="interface-icon"]')).toBeInTheDocument();
+ });
+});
diff --git a/src/components/WalletIcon.tsx b/src/components/WalletIcon.tsx
new file mode 100644
index 00000000000..17ef590a251
--- /dev/null
+++ b/src/components/WalletIcon.tsx
@@ -0,0 +1,46 @@
+import { defaultWallet, IWallet } from '@mycrypto/wallet-list';
+
+import { Box, Icon, Text, TIcon } from '@components';
+
+export const WalletIcon = ({
+ wallet,
+ interfaceIcon
+}: {
+ wallet: IWallet;
+ interfaceIcon?: TIcon;
+}) => (
+
+
+
+ {wallet.name}
+
+ {interfaceIcon && (
+
+
+
+ )}
+
+);
diff --git a/src/components/WalletTag.test.tsx b/src/components/WalletTag.test.tsx
new file mode 100644
index 00000000000..87f937a29bb
--- /dev/null
+++ b/src/components/WalletTag.test.tsx
@@ -0,0 +1,19 @@
+import { WalletTags } from '@mycrypto/wallet-list';
+import { simpleRender } from 'test-utils';
+
+import { translateRaw } from '@translations';
+
+import { WalletTag } from './WalletTag';
+
+const renderComponent = ({ tag }: { tag: WalletTags }) => {
+ return simpleRender();
+};
+
+describe('WalletTag', () => {
+ test('it can render a WalletTag', () => {
+ const props = { tag: WalletTags.Desktop };
+ const { getByText } = renderComponent(props);
+
+ expect(getByText(translateRaw('WALLET_TAG_DESKTOP'), { exact: false })).toBeInTheDocument();
+ });
+});
diff --git a/src/components/WalletTag.tsx b/src/components/WalletTag.tsx
new file mode 100644
index 00000000000..925c6128350
--- /dev/null
+++ b/src/components/WalletTag.tsx
@@ -0,0 +1,17 @@
+import { WalletTags } from '@mycrypto/wallet-list';
+
+import { Body, Box, Icon } from '@components';
+import { getWalletTag } from '@config';
+
+export const WalletTag = ({ tag }: { tag: WalletTags }) => {
+ const tagConfig = getWalletTag(tag);
+
+ return (
+
+
+
+ {tagConfig.text}
+
+
+ );
+};
diff --git a/src/components/WalletUnlock/ViewOnly.test.tsx b/src/components/WalletUnlock/ViewOnly.test.tsx
new file mode 100644
index 00000000000..d39e27d9e99
--- /dev/null
+++ b/src/components/WalletUnlock/ViewOnly.test.tsx
@@ -0,0 +1,35 @@
+import { IWallet, wallets } from '@mycrypto/wallet-list';
+import { simpleRender } from 'test-utils';
+
+import { translateRaw } from '@translations';
+import { FormData } from '@types';
+
+import { ViewOnlyDecrypt } from './ViewOnly';
+
+const defaultProps: React.ComponentProps = {
+ formData: ({ network: 'Ethereum' } as unknown) as FormData,
+ onUnlock: jest.fn()
+};
+
+const getComponent = ({ walletInfos }: { walletInfos?: IWallet }) => {
+ return simpleRender();
+};
+
+describe('ViewOnly', () => {
+ it('render', () => {
+ const { getByText } = getComponent({});
+
+ expect(getByText(translateRaw('INPUT_PUBLIC_ADDRESS_LABEL'))).toBeInTheDocument();
+ });
+
+ it('render with wallet infos', () => {
+ const wallet = wallets.find((wallet) => wallet.id === 'portis')!;
+ const props = { walletInfos: wallet };
+ const { getByText, getAllByText } = getComponent(props);
+
+ expect(getAllByText('Portis')).toBeTruthy();
+ expect(
+ getByText(translateRaw('VIEW_ONLY_HEADING', { $wallet: wallet.name }))
+ ).toBeInTheDocument();
+ });
+});
diff --git a/src/components/WalletUnlock/ViewOnly.tsx b/src/components/WalletUnlock/ViewOnly.tsx
index 565d0a54a9c..220949418f4 100644
--- a/src/components/WalletUnlock/ViewOnly.tsx
+++ b/src/components/WalletUnlock/ViewOnly.tsx
@@ -1,10 +1,11 @@
import { useState } from 'react';
+import { IWallet } from '@mycrypto/wallet-list';
import { Form, Formik } from 'formik';
import equals from 'ramda/src/equals';
import styled from 'styled-components';
-import { Body, Box, Button, ContactLookupField, Heading } from '@components';
+import { Body, Box, Button, ContactLookupField, Heading, WalletIcon, WalletTag } from '@components';
import { getKBHelpArticle, KB_HELP_ARTICLE } from '@config';
import { useNetworks } from '@services/Store';
import { WalletFactory } from '@services/WalletService';
@@ -24,6 +25,7 @@ const ButtonWrapper = styled(Button)`
interface Props {
formData: FormData;
onUnlock(param: any): void;
+ walletInfos?: IWallet;
}
const WalletService = WalletFactory[WalletId.VIEW_ONLY];
@@ -39,7 +41,7 @@ const initialFormikValues: FormValues = {
}
};
-export function ViewOnlyDecrypt({ formData, onUnlock }: Props) {
+export function ViewOnlyDecrypt({ formData, onUnlock, walletInfos }: Props) {
const { getNetworkById } = useNetworks();
const [isResolvingDomain, setIsResolvingDomain] = useState(false);
const [network] = useState(getNetworkById(formData.network));
@@ -55,13 +57,25 @@ export function ViewOnlyDecrypt({ formData, onUnlock }: Props) {
return (
+ {walletInfos && (
+
+
+
+ {walletInfos.tags && walletInfos.tags.map((tag, i) => )}
+
+
+ )}
- {translateRaw('INPUT_PUBLIC_ADDRESS_LABEL')}
+ {walletInfos
+ ? translateRaw('VIEW_ONLY_HEADING', { $wallet: walletInfos.name })
+ : translateRaw('INPUT_PUBLIC_ADDRESS_LABEL')}
- {translate('VIEW_ONLY_ADDR_DISCLAIMER', {
- $link: getKBHelpArticle(KB_HELP_ARTICLE.HOW_DOES_VIEW_ADDRESS_WORK)
- })}
+ {walletInfos
+ ? translateRaw('VIEW_ONLY_SUBHEADING')
+ : translate('VIEW_ONLY_ADDR_DISCLAIMER', {
+ $link: getKBHelpArticle(KB_HELP_ARTICLE.HOW_DOES_VIEW_ADDRESS_WORK)
+ })}
{({ errors, touched, values, setFieldError, setFieldTouched, setFieldValue }) => (
@@ -76,6 +90,9 @@ export function ViewOnlyDecrypt({ formData, onUnlock }: Props) {
setFieldValue={setFieldValue}
setFieldTouched={setFieldTouched}
setFieldError={setFieldError}
+ placeholder={
+ walletInfos && translateRaw('VIEW_ONLY_PLACEHOLDER', { $wallet: walletInfos.name })
+ }
/>
= {
+ useWalletConnectProps: ({
+ state: {
+ detectedAddress: '0x0000' as TAddress,
+ requestConnection: jest.fn(),
+ signMessage: jest.fn(),
+ kill: jest.fn()
+ }
+ } as unknown) as IUseWalletConnect,
+ goToPreviousStep: jest.fn(),
+ onUnlock: jest.fn()
+};
+
+const getComponent = ({ walletInfos }: { walletInfos?: IWallet }) => {
+ return simpleRender();
+};
+
+describe('WalletConnect', () => {
+ it('render', () => {
+ const { getByText } = getComponent({});
+
+ expect(
+ getByText(
+ translateRaw('SIGNER_SELECT_WALLETCONNECT', {
+ $walletId: translateRaw('X_WALLETCONNECT')
+ })
+ )
+ ).toBeInTheDocument();
+ expect(
+ getByText(
+ translateRaw('SIGNER_SELECT_WALLET_QR', { $walletId: translateRaw('X_WALLETCONNECT') })
+ )
+ ).toBeInTheDocument();
+ });
+
+ it('render with wallet infos', () => {
+ const wallet = wallets.find((wallet) => wallet.id === 'argent')!;
+ const props = { walletInfos: wallet };
+ const { getByText, getAllByText } = getComponent(props);
+
+ expect(getAllByText('Argent')).toBeTruthy();
+ expect(
+ getByText(translateRaw('WALLET_CONNECT_HEADER', { $wallet: wallet.name }))
+ ).toBeInTheDocument();
+ });
+});
diff --git a/src/components/WalletUnlock/WalletConnect.tsx b/src/components/WalletUnlock/WalletConnect.tsx
index 312be64bb3f..a38f86e6641 100644
--- a/src/components/WalletUnlock/WalletConnect.tsx
+++ b/src/components/WalletUnlock/WalletConnect.tsx
@@ -1,9 +1,19 @@
import { useEffect } from 'react';
+import { IWallet } from '@mycrypto/wallet-list';
import isEmpty from 'ramda/src/isEmpty';
import styled, { css } from 'styled-components';
-import { BusyBottom, Button, Overlay, QRCodeContainer, Typography } from '@components';
+import {
+ Box,
+ BusyBottom,
+ Button,
+ Overlay,
+ QRCodeContainer,
+ Typography,
+ WalletIcon,
+ WalletTag
+} from '@components';
import { IUseWalletConnect, WalletFactory } from '@services/WalletService';
import { BREAK_POINTS, COLORS, FONT_SIZE } from '@theme';
import translate, { translateRaw } from '@translations';
@@ -13,6 +23,7 @@ interface OwnProps {
useWalletConnectProps: IUseWalletConnect;
onUnlock(param: any): void;
goToPreviousStep(): void;
+ walletInfos?: IWallet;
}
const SHeader = styled.div`
@@ -65,7 +76,7 @@ const SContainer = styled.div`
const WalletService = WalletFactory[WalletId.WALLETCONNECT];
-export function WalletConnectDecrypt({ onUnlock, useWalletConnectProps }: OwnProps) {
+export function WalletConnectDecrypt({ onUnlock, useWalletConnectProps, walletInfos }: OwnProps) {
const { state, requestConnection, signMessage, kill } = useWalletConnectProps;
useEffect(() => {
@@ -81,14 +92,26 @@ export function WalletConnectDecrypt({ onUnlock, useWalletConnectProps }: OwnPro
return (
<>
+ {walletInfos && (
+
+
+
+ {walletInfos.tags && walletInfos.tags.map((tag, i) => )}
+
+
+ )}
- {translateRaw('SIGNER_SELECT_WALLETCONNECT', {
- $walletId: translateRaw('X_WALLETCONNECT')
- })}
+ {walletInfos
+ ? translateRaw('WALLET_CONNECT_HEADER', { $wallet: walletInfos.name })
+ : translateRaw('SIGNER_SELECT_WALLETCONNECT', {
+ $walletId: translateRaw('X_WALLETCONNECT')
+ })}
- {translate('SIGNER_SELECT_WALLET_QR', { $walletId: translateRaw('X_WALLETCONNECT') })}
+ {walletInfos
+ ? translateRaw('WALLET_CONNECT_SUBHEADING', { $wallet: walletInfos.name })
+ : translate('SIGNER_SELECT_WALLET_QR', { $walletId: translateRaw('X_WALLETCONNECT') })}
diff --git a/src/components/index.ts b/src/components/index.ts
index 9961e3cfc48..e155f3fb5dd 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -80,3 +80,5 @@ export { Switch } from './Switch';
export { BusyBottom } from './BusyBottom';
export { TransactionFeeEIP1559 } from './TransactionFeeEIP1559';
export { Identicon } from './Identicon';
+export { WalletIcon } from './WalletIcon';
+export { WalletTag } from './WalletTag';
diff --git a/src/config/index.ts b/src/config/index.ts
index df8d57ae636..c08f378ba16 100644
--- a/src/config/index.ts
+++ b/src/config/index.ts
@@ -39,3 +39,4 @@ export * from './txTypes';
export { STATIC_CONTACTS } from './staticContacts';
export { getFiat } from './fiats';
export * from './poapPromos';
+export * from './walletTags';
diff --git a/src/config/routePaths.ts b/src/config/routePaths.ts
index 8d76ebc070d..231c0002116 100644
--- a/src/config/routePaths.ts
+++ b/src/config/routePaths.ts
@@ -147,6 +147,11 @@ const PATHS: IRoutePath[] = [
name: 'NFT_DASHBOARD',
title: 'NFT Dashboard',
path: '/nft-dashboard'
+ },
+ {
+ name: 'ONBOARDING',
+ title: 'Onboarding',
+ path: '/onboarding'
}
];
diff --git a/src/config/walletTags.test.ts b/src/config/walletTags.test.ts
new file mode 100644
index 00000000000..71b6cd6f252
--- /dev/null
+++ b/src/config/walletTags.test.ts
@@ -0,0 +1,44 @@
+import { WalletTags } from '@mycrypto/wallet-list';
+
+import { translateRaw } from '@translations';
+
+import { getWalletTag } from './walletTags';
+
+describe('getWalletTag()', () => {
+ it('can return WalletTag config', () => {
+ expect(getWalletTag(WalletTags.Hardware)).toEqual({
+ icon: 'hardware-tag',
+ text: translateRaw('WALLET_TAG_HARDWARE')
+ });
+
+ expect(getWalletTag(WalletTags.Web)).toEqual({
+ icon: 'web-tag',
+ text: translateRaw('WALLET_TAG_WEB')
+ });
+
+ expect(getWalletTag(WalletTags.Mobile)).toEqual({
+ icon: 'mobile-tag',
+ text: translateRaw('WALLET_TAG_MOBILE')
+ });
+
+ expect(getWalletTag(WalletTags.Desktop)).toEqual({
+ icon: 'desktop-tag',
+ text: translateRaw('WALLET_TAG_DESKTOP')
+ });
+
+ expect(getWalletTag(WalletTags.Exchange)).toEqual({
+ icon: 'exchange-tag',
+ text: translateRaw('WALLET_TAG_EXCHANGE')
+ });
+
+ expect(getWalletTag(WalletTags.WalletConnect)).toEqual({
+ icon: 'walletconnect-tag',
+ text: translateRaw('WALLET_TAG_WALLET_CONNECT')
+ });
+
+ expect(getWalletTag(WalletTags.Other)).toEqual({
+ icon: 'other-tag',
+ text: translateRaw('WALLET_TAG_OTHER')
+ });
+ });
+});
diff --git a/src/config/walletTags.ts b/src/config/walletTags.ts
new file mode 100644
index 00000000000..0e41d573f01
--- /dev/null
+++ b/src/config/walletTags.ts
@@ -0,0 +1,44 @@
+import { WalletTags } from '@mycrypto/wallet-list';
+
+import { TIcon } from '@components';
+import { translateRaw } from '@translations';
+
+export const getWalletTag = (tag: WalletTags): { icon: TIcon; text: string } => {
+ switch (tag) {
+ case WalletTags.Hardware:
+ return {
+ icon: 'hardware-tag',
+ text: translateRaw('WALLET_TAG_HARDWARE')
+ };
+ case WalletTags.Web:
+ return {
+ icon: 'web-tag',
+ text: translateRaw('WALLET_TAG_WEB')
+ };
+ case WalletTags.Mobile:
+ return {
+ icon: 'mobile-tag',
+ text: translateRaw('WALLET_TAG_MOBILE')
+ };
+ case WalletTags.Desktop:
+ return {
+ icon: 'desktop-tag',
+ text: translateRaw('WALLET_TAG_DESKTOP')
+ };
+ case WalletTags.Exchange:
+ return {
+ icon: 'exchange-tag',
+ text: translateRaw('WALLET_TAG_EXCHANGE')
+ };
+ case WalletTags.WalletConnect:
+ return {
+ icon: 'walletconnect-tag',
+ text: translateRaw('WALLET_TAG_WALLET_CONNECT')
+ };
+ case WalletTags.Other:
+ return {
+ icon: 'other-tag',
+ text: translateRaw('WALLET_TAG_OTHER')
+ };
+ }
+};
diff --git a/src/features/AddAccount/AddAccountFlow.tsx b/src/features/AddAccount/AddAccountFlow.tsx
index 35ecc3d941f..2ece23745df 100644
--- a/src/features/AddAccount/AddAccountFlow.tsx
+++ b/src/features/AddAccount/AddAccountFlow.tsx
@@ -1,5 +1,6 @@
import { useEffect, useReducer, useState } from 'react';
+import { IWallet, WalletConnectivity } from '@mycrypto/wallet-list';
import { withRouter } from 'react-router-dom';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
@@ -8,6 +9,7 @@ import { IWalletConfig, ROUTE_PATHS, WALLETS_CONFIG } from '@config';
import { useDispatch } from '@store';
import { addNewAccounts } from '@store/account.slice';
import { IStory, WalletId } from '@types';
+import { getFromWalletList, isValidWalletListId } from '@utils';
import { useUpdateEffect } from '@vendor';
import { formReducer, initialState } from './AddAccountForm.reducer';
@@ -30,6 +32,21 @@ export const isValidWalletId = (id: WalletId | string | undefined) => {
return !!(id && Object.values(WalletId).includes(id as WalletId));
};
+export const getAccountTypeFromWallet = (wallet: IWallet) => {
+ switch (wallet.connectivity) {
+ case WalletConnectivity.WalletConnect:
+ return WalletId.WALLETCONNECT;
+ case WalletConnectivity.ViewOnly:
+ case WalletConnectivity.MigrateNonCustodial:
+ return WalletId.VIEW_ONLY;
+ case WalletConnectivity.Web3:
+ return WalletId.WEB3;
+ case WalletConnectivity.Ledger:
+ return WalletId.LEDGER_NANO_S_NEW;
+ case WalletConnectivity.Trezor:
+ return WalletId.TREZOR_NEW;
+ }
+};
/*
Flow to add an account to database. The default view of the component
displays a list of wallets (e.g. stories) that each posses their own number
@@ -39,6 +56,7 @@ export const isValidWalletId = (id: WalletId | string | undefined) => {
*/
const AddAccountFlow = withRouter(({ history, match }) => {
const dispatch = useDispatch();
+ const [wallet, setWallet] = useState();
const [step, setStep] = useState(0); // The current Step inside the Wallet Story.
const [formData, updateFormState] = useReducer(formReducer, initialState); // The data that we want to save at the end.
@@ -60,13 +78,22 @@ const AddAccountFlow = withRouter(({ history, match }) => {
const { walletId } = match.params; // Read the walletName parameter from the URL
if (!walletId) {
return;
- } else if (!isValidWalletId(walletId.toUpperCase())) {
+ } else if (!isValidWalletId(walletId.toUpperCase()) && !isValidWalletListId(walletId)) {
goToStart();
} else if (walletId.toUpperCase() !== storyName) {
- updateFormState({
- type: ActionType.SELECT_ACCOUNT_TYPE,
- payload: { accountType: walletId.toUpperCase() }
- });
+ const selectedWallet = getFromWalletList(walletId);
+ if (selectedWallet) {
+ setWallet(selectedWallet);
+ updateFormState({
+ type: ActionType.SELECT_ACCOUNT_TYPE,
+ payload: { accountType: getAccountTypeFromWallet(selectedWallet) }
+ });
+ } else {
+ updateFormState({
+ type: ActionType.SELECT_ACCOUNT_TYPE,
+ payload: { accountType: walletId.toUpperCase() }
+ });
+ }
}
}, [match.params]);
@@ -123,6 +150,7 @@ const AddAccountFlow = withRouter(({ history, match }) => {
{
});
});
+describe('getAccountTypeFromWallet()', () => {
+ it('returns correct WalletId', () => {
+ const walletConnectWallet = wallets.find(
+ (wallet) => wallet.connectivity === WalletConnectivity.WalletConnect
+ );
+ const viewOnlyWallet = wallets.find(
+ (wallet) => wallet.connectivity === WalletConnectivity.ViewOnly
+ );
+ const web3Wallet = wallets.find((wallet) => wallet.connectivity === WalletConnectivity.Web3);
+ const ledgerWallet = wallets.find(
+ (wallet) => wallet.connectivity === WalletConnectivity.Ledger
+ );
+ const trezorWallet = wallets.find(
+ (wallet) => wallet.connectivity === WalletConnectivity.Trezor
+ );
+ expect(getAccountTypeFromWallet(walletConnectWallet!)).toEqual(WalletId.WALLETCONNECT);
+ expect(getAccountTypeFromWallet(viewOnlyWallet!)).toEqual(WalletId.VIEW_ONLY);
+ expect(getAccountTypeFromWallet(web3Wallet!)).toEqual(WalletId.WEB3);
+ expect(getAccountTypeFromWallet(ledgerWallet!)).toEqual(WalletId.LEDGER_NANO_S_NEW);
+ expect(getAccountTypeFromWallet(trezorWallet!)).toEqual(WalletId.TREZOR_NEW);
+ });
+});
+
/* Test components */
describe('AddAccountFlow', () => {
let history: any;
diff --git a/src/features/Onboarding/OnboardingFlow.tsx b/src/features/Onboarding/OnboardingFlow.tsx
new file mode 100644
index 00000000000..59e0df796df
--- /dev/null
+++ b/src/features/Onboarding/OnboardingFlow.tsx
@@ -0,0 +1,46 @@
+import { useEffect, useState } from 'react';
+
+import { IWallet, WalletConnectivity } from '@mycrypto/wallet-list';
+import { useHistory, useRouteMatch } from 'react-router';
+
+import { AppLoading, ExtendedContentPanel } from '@components';
+import { ROUTE_PATHS } from '@config';
+import { getFromWalletList, isValidWalletListId } from '@utils';
+
+import { Migrate } from './components';
+
+export const isMigratableWallet = (wallet: IWallet) =>
+ wallet.connectivity === WalletConnectivity.MigrateCustodial ||
+ wallet.connectivity === WalletConnectivity.MigrateNonCustodial;
+
+const OnboardingFlow = () => {
+ const [wallet, setWallet] = useState();
+ const history = useHistory();
+ const match = useRouteMatch<{ walletId: string | undefined }>();
+
+ useEffect(() => {
+ const { walletId } = match.params;
+ if (!walletId) {
+ return;
+ } else if (!isValidWalletListId(walletId)) {
+ history.replace(`${ROUTE_PATHS.ADD_ACCOUNT.path}`);
+ } else {
+ const selectedWallet = getFromWalletList(walletId);
+ if (selectedWallet && isMigratableWallet(selectedWallet)) {
+ setWallet(selectedWallet);
+ } else if (selectedWallet && !isMigratableWallet(selectedWallet)) {
+ history.replace(`${ROUTE_PATHS.ADD_ACCOUNT.path}/${selectedWallet.id}`);
+ } else {
+ history.replace(`${ROUTE_PATHS.ADD_ACCOUNT.path}`);
+ }
+ }
+ }, [match.params]);
+
+ return (
+
+ {wallet ? : }
+
+ );
+};
+
+export default OnboardingFlow;
diff --git a/src/features/Onboarding/__tests__/Migrate.test.tsx b/src/features/Onboarding/__tests__/Migrate.test.tsx
new file mode 100644
index 00000000000..6e817df56aa
--- /dev/null
+++ b/src/features/Onboarding/__tests__/Migrate.test.tsx
@@ -0,0 +1,26 @@
+import { IWallet, wallets } from '@mycrypto/wallet-list';
+import { simpleRender } from 'test-utils';
+
+import { translateRaw } from '@translations';
+
+import Migrate from '../components/Migrate';
+
+const renderComponent = ({ walletInfos }: { walletInfos: IWallet }) => {
+ return simpleRender();
+};
+
+describe('Migrate', () => {
+ it('Can render a Migration guide', () => {
+ const wallet = wallets.find((wallet) => wallet.id === 'kraken')!;
+ const props = { walletInfos: wallet };
+ const { getAllByText, getByText } = renderComponent(props);
+
+ expect(getAllByText(wallet.name, { exact: false })).toBeTruthy();
+ expect(getByText(translateRaw('WALLET_TAG_EXCHANGE'), { exact: false })).toBeInTheDocument();
+ expect(
+ getByText(translateRaw('MIGRATE_GET_HELP_LINK', { $exchange: wallet.name }), {
+ exact: false
+ })
+ ).toBeInTheDocument();
+ });
+});
diff --git a/src/features/Onboarding/__tests__/config.test.ts b/src/features/Onboarding/__tests__/config.test.ts
new file mode 100644
index 00000000000..d267cbd950c
--- /dev/null
+++ b/src/features/Onboarding/__tests__/config.test.ts
@@ -0,0 +1,18 @@
+import { WalletConnectivity, wallets } from '@mycrypto/wallet-list';
+
+import { getMigrationGuide } from '../config';
+
+describe('getMigrationGuide()', () => {
+ it('can return migration config', () => {
+ const custodialExchange = wallets.find(
+ (wallet) => wallet.connectivity === WalletConnectivity.MigrateCustodial
+ );
+
+ const nonCustodialExchange = wallets.find(
+ (wallet) => wallet.connectivity === WalletConnectivity.MigrateNonCustodial
+ );
+
+ expect(getMigrationGuide(custodialExchange!)).toBeTruthy();
+ expect(getMigrationGuide(nonCustodialExchange!)).toBeTruthy();
+ });
+});
diff --git a/src/features/Onboarding/components/Migrate.tsx b/src/features/Onboarding/components/Migrate.tsx
new file mode 100644
index 00000000000..074f9faccb4
--- /dev/null
+++ b/src/features/Onboarding/components/Migrate.tsx
@@ -0,0 +1,63 @@
+import { IWallet } from '@mycrypto/wallet-list';
+
+import { Body, Box, Button, Heading, LinkApp, WalletIcon, WalletTag } from '@components';
+import { translateRaw } from '@translations';
+
+import { getMigrationGuide } from '../config';
+
+const Migrate = ({ walletInfos }: { walletInfos: IWallet }) => {
+ const config = getMigrationGuide(walletInfos)!;
+
+ return (
+
+
+
+
+ {walletInfos.tags && walletInfos.tags.map((tag, i) => )}
+
+
+
+ {translateRaw('MIGRATE_HEADING', { $exchange: walletInfos.name })}
+
+
+ {config.subheading}
+
+
+
+
+
+
+
+
+ {translateRaw('MIGRATE_HOW_TO_TRANSFER')}
+
+ {config.steps.map((step, i) => (
+
+
+ {`0${i + 1}`}
+
+ {step}
+
+ ))}
+
+
+
+
+
+
+ {walletInfos.urls.support && (
+
+ {translateRaw('MIGRATE_GET_HELP_TEXT')}{' '}
+
+ {translateRaw('MIGRATE_GET_HELP_LINK', { $exchange: walletInfos.name })}
+
+
+ )}
+
+
+ );
+};
+
+export default Migrate;
diff --git a/src/features/Onboarding/components/index.ts b/src/features/Onboarding/components/index.ts
new file mode 100644
index 00000000000..548f24291b9
--- /dev/null
+++ b/src/features/Onboarding/components/index.ts
@@ -0,0 +1 @@
+export { default as Migrate } from './Migrate';
diff --git a/src/features/Onboarding/config.ts b/src/features/Onboarding/config.ts
new file mode 100644
index 00000000000..29b0223bc08
--- /dev/null
+++ b/src/features/Onboarding/config.ts
@@ -0,0 +1,49 @@
+import { IWallet, WalletConnectivity } from '@mycrypto/wallet-list';
+
+import { ROUTE_PATHS } from '@config';
+import { translateRaw } from '@translations';
+
+export const getMigrationGuide = (wallet: IWallet) => {
+ if (wallet.connectivity === WalletConnectivity.MigrateCustodial)
+ return {
+ subheading: translateRaw('MIGRATE_CUSTODIAL_SUBHEADING', { $exchange: wallet.name }),
+ topButton: {
+ to: ROUTE_PATHS.DOWNLOAD_DESKTOP_APP.path,
+ text: translateRaw('BUSY_BOTTOM_GENERAL_1')
+ },
+ primaryButton: {
+ to: ROUTE_PATHS.DOWNLOAD_DESKTOP_APP.path,
+ text: translateRaw('BUSY_BOTTOM_GENERAL_1')
+ },
+ secondaryButton: {
+ to: ROUTE_PATHS.ADD_ACCOUNT.path,
+ text: translateRaw('MIGRATE_CONNECT_ACCOUNT')
+ },
+ steps: [
+ translateRaw('MIGRATE_CUSTODIAL_01'),
+ translateRaw('MIGRATE_CUSTODIAL_02', { $exchange: wallet.name }),
+ translateRaw('MIGRATE_CUSTODIAL_03')
+ ]
+ };
+ if (wallet.connectivity === WalletConnectivity.MigrateNonCustodial)
+ return {
+ subheading: translateRaw('MIGRATE_NON_CUSTODIAL_SUBHEADING', { $exchange: wallet.name }),
+ topButton: {
+ to: `${ROUTE_PATHS.ADD_ACCOUNT.path}/${wallet.id}`,
+ text: translateRaw('MIGRATE_NON_CUSTODIAL_TOP_BUTTON', { $exchange: wallet.name })
+ },
+ primaryButton: {
+ to: ROUTE_PATHS.DOWNLOAD_DESKTOP_APP.path,
+ text: translateRaw('BUSY_BOTTOM_GENERAL_1')
+ },
+ secondaryButton: {
+ to: ROUTE_PATHS.ADD_ACCOUNT.path,
+ text: translateRaw('MIGRATE_CONNECT_ACCOUNT')
+ },
+ steps: [
+ translateRaw('MIGRATE_NON_CUSTODIAL_01', { $exchange: wallet.name }),
+ translateRaw('MIGRATE_NON_CUSTODIAL_02'),
+ translateRaw('MIGRATE_NON_CUSTODIAL_03', { $exchange: wallet.name })
+ ]
+ };
+};
diff --git a/src/features/Onboarding/index.ts b/src/features/Onboarding/index.ts
new file mode 100644
index 00000000000..17e3f57a7ab
--- /dev/null
+++ b/src/features/Onboarding/index.ts
@@ -0,0 +1 @@
+export { default as OnboardingFlow } from './OnboardingFlow';
diff --git a/src/routing/routes.tsx b/src/routing/routes.tsx
index 870d5f93346..d7a083daec3 100644
--- a/src/routing/routes.tsx
+++ b/src/routing/routes.tsx
@@ -95,6 +95,10 @@ const GolemTokenMigration = lazy(() =>
import(/* webpackChunkName: "TokenMigration" */ '@features/GolemTokenMigration')
);
+const OnboardingFlow = lazy(() =>
+ import(/* webpackChunkName: "Onboarding" */ '@features/Onboarding/OnboardingFlow')
+);
+
export interface IAppRoutes {
[K: string]: IAppRoute;
}
@@ -329,6 +333,14 @@ export const getStaticAppRoutes = (featureFlags: FeatureFlags): IAppRoute[] => [
requireAccounts: true,
enabled: true,
component: NftDashboard
+ },
+ {
+ name: ROUTE_PATHS.ONBOARDING.name,
+ title: ROUTE_PATHS.ONBOARDING.title,
+ path: `${ROUTE_PATHS.ONBOARDING.path}/:walletId?`,
+ enabled: true,
+ exact: true,
+ component: OnboardingFlow
}
];
diff --git a/src/translations/lang/en.json b/src/translations/lang/en.json
index 7c49c42715f..7554d4ddbe4 100644
--- a/src/translations/lang/en.json
+++ b/src/translations/lang/en.json
@@ -1078,6 +1078,32 @@
"MEMBERSHIP_POAP": "Regular POAP NFT drops",
"MEMBERSHIP_TREZOR": "10% Discount for Trezor Hardware Wallets",
"MEMBERSHIP_FAUCET": "Extra Faucet Testnet ETH (Rinkeby, Ropsten, Kovan, Goerli)",
- "MEMBERSHIP_CITADEL": "Access to the exclusive MyCrypto Citadel"
+ "MEMBERSHIP_CITADEL": "Access to the exclusive MyCrypto Citadel",
+ "VIEW_ONLY_HEADING": "We’re not fully integrated with $wallet yet",
+ "VIEW_ONLY_SUBHEADING": "You can still see your assets in view-only mode on your MyCrypto dashboard for now",
+ "VIEW_ONLY_PLACEHOLDER": "Enter your $wallet address",
+ "WALLET_CONNECT_HEADER": "Connect to $wallet via WalletConnect",
+ "WALLET_CONNECT_SUBHEADING": "Open your $wallet app and scan the WalletConnect QR code below.",
+ "MIGRATE_HEADING": "Migrate from $exchange",
+ "MIGRATE_CONNECT_ACCOUNT": "Connect Account",
+ "MIGRATE_CUSTODIAL_SUBHEADING": "$exchange is a custodial service, meaning they hold your crypto on your behalf. If you wish to take full control of your assets, MyCrypto will help you get there. You'll start by creating a new MyCrypto account, and then you'll migrate your crypto off of $exchange and to that new MyCrypto account. We'll walk you through it:",
+ "MIGRATE_CUSTODIAL_01": "Click below to create a new MyCrypto account or connect an existing account. Copy the account address to your clipboard.",
+ "MIGRATE_CUSTODIAL_02": "Login to your $exchange account and safely follow the steps for withdrawing your cryptocurrency. Make sure to only select cryptocurrencies supported by MyCrypto.",
+ "MIGRATE_CUSTODIAL_03": "When the time comes to insert a withdrawal address, input the address you created/connected in step one. Verify that it matches, and then continue with the withdrawal and send your cryptocurrency to that address.",
+ "MIGRATE_NON_CUSTODIAL_SUBHEADING": "Tracking your account is limited and you cannot take action on that account. To manage your $exchange assets on MyCrypto, you'll need to migrate.",
+ "MIGRATE_NON_CUSTODIAL_TOP_BUTTON": "Track your $exchange account",
+ "MIGRATE_NON_CUSTODIAL_01": "Find your $exchange recovery phrase within the $exchange app.",
+ "MIGRATE_NON_CUSTODIAL_02": "Download and install the MyCrypto Desktop App or the MyCrypto Signer App.",
+ "MIGRATE_NON_CUSTODIAL_03": "Click Add Account in the MyCrypto application that you've installed. Then select \"Mnemonic Phrase\" and enter the key you obtained from $exchange",
+ "MIGRATE_GET_HELP_TEXT": "Not sure where to start?",
+ "MIGRATE_GET_HELP_LINK": "Get migration help for $exchange",
+ "MIGRATE_HOW_TO_TRANSFER": "How to Transfer",
+ "WALLET_TAG_HARDWARE": "Hardware Wallet",
+ "WALLET_TAG_WEB": "Browser-Based",
+ "WALLET_TAG_MOBILE": "Mobile",
+ "WALLET_TAG_DESKTOP": "Desktop",
+ "WALLET_TAG_EXCHANGE": "Exchange",
+ "WALLET_TAG_WALLET_CONNECT": "via Wallet Connect",
+ "WALLET_TAG_OTHER": "Other"
}
}
diff --git a/src/utils/wallets.ts b/src/utils/wallets.ts
index b71ba1dec12..db5cdea0b38 100644
--- a/src/utils/wallets.ts
+++ b/src/utils/wallets.ts
@@ -1,3 +1,5 @@
+import { wallets } from '@mycrypto/wallet-list';
+
import { NetworkId, StoreAccount, TAddress, WalletId } from '@types';
import { isSameAddress } from '@utils';
@@ -30,3 +32,7 @@ export const isSenderAccountPresent = (
accounts.some(
({ address, wallet }) => isSameAddress(address, addressToCheck) && !isViewOnlyWallet(wallet)
);
+
+export const isValidWalletListId = (id: string) => !!wallets.find((wallet) => wallet.id === id);
+
+export const getFromWalletList = (id: string) => wallets.find((wallet) => wallet.id === id);
diff --git a/yarn.lock b/yarn.lock
index 30994821332..d6cac27f3ad 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3091,6 +3091,13 @@
dependencies:
"@findeth/abi" "^0.7.1"
+"@mycrypto/wallet-list@1.3.0":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@mycrypto/wallet-list/-/wallet-list-1.3.0.tgz#c45cda8908775fa0378ae0259dfad6ac9e88129c"
+ integrity sha512-d+vinjhOnIGjWzjP99nOXam5pxGV9YEn4t+QQSZyZ22YCNbvRjOvrXXjShBUzZtLDgmTAcyMCIoWOrwzk06ktQ==
+ dependencies:
+ remove "^0.1.5"
+
"@mycrypto/wallets@1.3.4":
version "1.3.4"
resolved "https://registry.yarnpkg.com/@mycrypto/wallets/-/wallets-1.3.4.tgz#2189c4a86fe907366d49984d49ba0030b73b64b6"
@@ -8119,6 +8126,13 @@ chai@^4.1.2:
pathval "^1.1.0"
type-detect "^4.0.5"
+"chainsaw@>=0.0.7 <0.1":
+ version "0.0.9"
+ resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.0.9.tgz#11a05102d1c4c785b6d0415d336d5a3a1612913e"
+ integrity sha1-EaBRAtHEx4W20EFdM21aOhYSkT4=
+ dependencies:
+ traverse ">=0.3.0 <0.4"
+
chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -12385,6 +12399,13 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
+"hashish@>=0.0.2 <0.1":
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/hashish/-/hashish-0.0.4.tgz#6d60bc6ffaf711b6afd60e426d077988014e6554"
+ integrity sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ=
+ dependencies:
+ traverse ">=0.2.4"
+
hast-to-hyperscript@^9.0.0:
version "9.0.1"
resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d"
@@ -19040,6 +19061,13 @@ remove-trailing-separator@^1.0.1:
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+remove@^0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/remove/-/remove-0.1.5.tgz#095ffd827d65c9f41ad97d33e416a75811079955"
+ integrity sha1-CV/9gn1lyfQa2X0z5BanWBEHmVU=
+ dependencies:
+ seq ">= 0.3.5"
+
renderkid@^2.0.4:
version "2.0.5"
resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.5.tgz#483b1ac59c6601ab30a7a596a5965cabccfdd0a5"
@@ -19655,6 +19683,14 @@ send@0.17.1:
range-parser "~1.2.1"
statuses "~1.5.0"
+"seq@>= 0.3.5":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/seq/-/seq-0.3.5.tgz#ae02af3a424793d8ccbf212d69174e0c54dffe38"
+ integrity sha1-rgKvOkJHk9jMvyEtaRdODFTf/jg=
+ dependencies:
+ chainsaw ">=0.0.7 <0.1"
+ hashish ">=0.0.2 <0.1"
+
serialize-javascript@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
@@ -21335,6 +21371,16 @@ tr46@^2.0.2:
dependencies:
punycode "^2.1.1"
+traverse@>=0.2.4:
+ version "0.6.6"
+ resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
+ integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=
+
+"traverse@>=0.3.0 <0.4":
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9"
+ integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=
+
tree-kill@^1.1.0, tree-kill@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"