From 9e9b275f223485b071993e5dd7622fb9eec62851 Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 4 Feb 2022 10:54:54 +0200 Subject: [PATCH 01/30] Set up ethers / context and wallet creation --- wallets/react-wallet-v2/package.json | 2 +- .../react-wallet-v2/src/components/Layout.tsx | 33 -------------- .../src/containers/GlobalLayout.tsx | 45 +++++++++++++++++++ .../src/contexts/WalletContext.tsx | 28 ++++++++---- wallets/react-wallet-v2/src/pages/_app.tsx | 2 +- .../react-wallet-v2/src/utils/WalletUtil.ts | 0 wallets/react-wallet-v2/yarn.lock | 8 ++-- 7 files changed, 71 insertions(+), 47 deletions(-) delete mode 100644 wallets/react-wallet-v2/src/components/Layout.tsx create mode 100644 wallets/react-wallet-v2/src/containers/GlobalLayout.tsx delete mode 100644 wallets/react-wallet-v2/src/utils/WalletUtil.ts diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 8cb0cc0..55c0e8a 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -21,7 +21,7 @@ "devDependencies": { "@walletconnect/types": "2.0.0-beta.22", "@types/node": "17.0.14", - "@types/react": "17.0.38", + "@types/react": "17.0.39", "eslint": "8.8.0", "eslint-config-next": "12.0.10", "eslint-config-prettier": "8.3.0", diff --git a/wallets/react-wallet-v2/src/components/Layout.tsx b/wallets/react-wallet-v2/src/components/Layout.tsx deleted file mode 100644 index 897f71b..0000000 --- a/wallets/react-wallet-v2/src/components/Layout.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Card, Container, Divider } from '@nextui-org/react' -import { ReactNode } from 'react' - -interface Props { - children: ReactNode | ReactNode[] -} - -export default function Layout({ children }: Props) { - return ( - - - Header - - - - {children} - - - - Footer - - - ) -} diff --git a/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx b/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx new file mode 100644 index 0000000..381adba --- /dev/null +++ b/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx @@ -0,0 +1,45 @@ +import { WalletContext } from '@/contexts/WalletContext' +import { Card, Container, Divider, Loading } from '@nextui-org/react' +import { Fragment, ReactNode, useContext, useEffect } from 'react' + +interface Props { + children: ReactNode | ReactNode[] +} + +export default function GlobalLayout({ children }: Props) { + const { state, actions } = useContext(WalletContext) + const hasWallet = state.wallet !== undefined + + useEffect(() => { + if (!hasWallet) { + actions.createWallet() + } + }, [actions, hasWallet]) + + return ( + + + {hasWallet ? ( + + Header + + {children} + + Footer + + ) : ( + + )} + + + ) +} diff --git a/wallets/react-wallet-v2/src/contexts/WalletContext.tsx b/wallets/react-wallet-v2/src/contexts/WalletContext.tsx index 35aa393..61648e2 100644 --- a/wallets/react-wallet-v2/src/contexts/WalletContext.tsx +++ b/wallets/react-wallet-v2/src/contexts/WalletContext.tsx @@ -1,27 +1,39 @@ +import { ethers } from 'ethers' import { createContext, ReactNode, useState } from 'react' /** * Types */ -interface State {} +interface State { + wallet: ethers.Wallet +} + +interface Actions { + createWallet: () => void +} + +interface Context { + state: State + actions: Actions +} interface Props { children: ReactNode | ReactNode[] } /** - * Context + * Context / Provider */ -export const WalletContext = createContext({}) +export const WalletContext = createContext({} as Context) -/** - * Provider - */ export function WalletContextProvider({ children }: Props) { - const [state, setState] = useState({}) + const [state, setState] = useState({ wallet: undefined }) const actions = { - async initialise() {} + createWallet() { + const wallet = ethers.Wallet.createRandom() + setState(s => ({ ...s, wallet })) + } } return {children} diff --git a/wallets/react-wallet-v2/src/pages/_app.tsx b/wallets/react-wallet-v2/src/pages/_app.tsx index a84ce84..ca36d7d 100644 --- a/wallets/react-wallet-v2/src/pages/_app.tsx +++ b/wallets/react-wallet-v2/src/pages/_app.tsx @@ -1,4 +1,4 @@ -import Layout from '@/components/Layout' +import Layout from '@/containers/GlobalLayout' import { WalletContextProvider } from '@/contexts/WalletContext' import { theme } from '@/utils/ThemeUtil' import { NextUIProvider } from '@nextui-org/react' diff --git a/wallets/react-wallet-v2/src/utils/WalletUtil.ts b/wallets/react-wallet-v2/src/utils/WalletUtil.ts deleted file mode 100644 index e69de29..0000000 diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index f1f7c15..895b7e7 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -565,10 +565,10 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== -"@types/react@17.0.38": - version "17.0.38" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd" - integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ== +"@types/react@17.0.39": + version "17.0.39" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" + integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" From 1f71001175ebaee43efe2cfe9a3a20dd55afbbd6 Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 4 Feb 2022 11:37:35 +0200 Subject: [PATCH 02/30] Init wallet and wallet connect client --- .../src/components/PageHeader.tsx | 2 +- .../src/containers/GlobalLayout.tsx | 30 ++++++++--- .../src/contexts/WalletContext.tsx | 54 +++++++++++++++---- wallets/react-wallet-v2/src/pages/_app.tsx | 3 +- .../react-wallet-v2/src/utils/ThemeUtil.ts | 5 -- 5 files changed, 68 insertions(+), 26 deletions(-) delete mode 100644 wallets/react-wallet-v2/src/utils/ThemeUtil.ts diff --git a/wallets/react-wallet-v2/src/components/PageHeader.tsx b/wallets/react-wallet-v2/src/components/PageHeader.tsx index ab1d5fc..b6f92fe 100644 --- a/wallets/react-wallet-v2/src/components/PageHeader.tsx +++ b/wallets/react-wallet-v2/src/components/PageHeader.tsx @@ -9,7 +9,7 @@ export default function PageHeader({ children }: Props) { diff --git a/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx b/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx index 381adba..3743af6 100644 --- a/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx +++ b/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx @@ -1,20 +1,28 @@ import { WalletContext } from '@/contexts/WalletContext' import { Card, Container, Divider, Loading } from '@nextui-org/react' -import { Fragment, ReactNode, useContext, useEffect } from 'react' +import { Fragment, ReactNode, useCallback, useContext, useEffect } from 'react' interface Props { children: ReactNode | ReactNode[] } export default function GlobalLayout({ children }: Props) { - const { state, actions } = useContext(WalletContext) - const hasWallet = state.wallet !== undefined + const { + state: { initialized }, + actions + } = useContext(WalletContext) + + const onInitialize = useCallback(async () => { + actions.createWallet() + await actions.createWalletConnectClient() + actions.setInitialized() + }, [actions]) useEffect(() => { - if (!hasWallet) { - actions.createWallet() + if (!initialized) { + onInitialize() } - }, [actions, hasWallet]) + }, [initialized, onInitialize]) return ( - {hasWallet ? ( + {initialized ? ( Header diff --git a/wallets/react-wallet-v2/src/contexts/WalletContext.tsx b/wallets/react-wallet-v2/src/contexts/WalletContext.tsx index 61648e2..1553383 100644 --- a/wallets/react-wallet-v2/src/contexts/WalletContext.tsx +++ b/wallets/react-wallet-v2/src/contexts/WalletContext.tsx @@ -1,15 +1,21 @@ -import { ethers } from 'ethers' -import { createContext, ReactNode, useState } from 'react' +import WalletConnectClient from '@walletconnect/client' +import { Wallet } from 'ethers' +import KeyValueStorage from 'keyvaluestorage' +import { createContext, ReactNode, useMemo, useState } from 'react' /** * Types */ interface State { - wallet: ethers.Wallet + initialized: boolean + wallet: Wallet + walletConnectClient: WalletConnectClient } interface Actions { + setInitialized: () => void createWallet: () => void + createWalletConnectClient: () => Promise } interface Context { @@ -27,14 +33,42 @@ interface Props { export const WalletContext = createContext({} as Context) export function WalletContextProvider({ children }: Props) { - const [state, setState] = useState({ wallet: undefined }) + const [state, setState] = useState({ + initialized: false, + wallet: undefined, + walletConnectClient: undefined + }) - const actions = { - createWallet() { - const wallet = ethers.Wallet.createRandom() - setState(s => ({ ...s, wallet })) - } - } + const actions = useMemo( + () => ({ + setInitialized() { + setState(s => ({ ...s, initialized: true })) + }, + + createWallet() { + const wallet = Wallet.createRandom() + setState(s => ({ ...s, wallet })) + }, + + async createWalletConnectClient() { + const walletConnectClient = await WalletConnectClient.init({ + controller: true, + logger: 'debug', + projectId: '8f331b9812e0e5b8f2da2c7203624869', + relayUrl: 'wss://relay.walletconnect.com', + metadata: { + name: 'React Wallet', + description: 'React Wallet for WalletConnect', + url: 'https://walletconnect.com/', + icons: ['https://avatars.githubusercontent.com/u/37784886'] + }, + storage: new KeyValueStorage() + }) + setState(s => ({ ...s, walletConnectClient })) + } + }), + [] + ) return {children} } diff --git a/wallets/react-wallet-v2/src/pages/_app.tsx b/wallets/react-wallet-v2/src/pages/_app.tsx index ca36d7d..5729b63 100644 --- a/wallets/react-wallet-v2/src/pages/_app.tsx +++ b/wallets/react-wallet-v2/src/pages/_app.tsx @@ -1,12 +1,11 @@ import Layout from '@/containers/GlobalLayout' import { WalletContextProvider } from '@/contexts/WalletContext' -import { theme } from '@/utils/ThemeUtil' import { NextUIProvider } from '@nextui-org/react' import { AppProps } from 'next/app' export default function App({ Component, pageProps }: AppProps) { return ( - + diff --git a/wallets/react-wallet-v2/src/utils/ThemeUtil.ts b/wallets/react-wallet-v2/src/utils/ThemeUtil.ts deleted file mode 100644 index 49f9f74..0000000 --- a/wallets/react-wallet-v2/src/utils/ThemeUtil.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createTheme } from '@nextui-org/react' - -export const theme = createTheme({ - type: 'dark' -}) From 81bddf0c5d5d6bcaf991c5f0b01e95f15caf281b Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 4 Feb 2022 12:01:08 +0200 Subject: [PATCH 03/30] Cleanup context --- .../src/components/PageHeader.tsx | 6 ++++ .../src/containers/GlobalLayout.tsx | 30 +++++++++++-------- .../src/contexts/AccountContext.tsx | 0 .../src/contexts/WalletContext.tsx | 18 ++++++----- 4 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 wallets/react-wallet-v2/src/contexts/AccountContext.tsx diff --git a/wallets/react-wallet-v2/src/components/PageHeader.tsx b/wallets/react-wallet-v2/src/components/PageHeader.tsx index b6f92fe..b187271 100644 --- a/wallets/react-wallet-v2/src/components/PageHeader.tsx +++ b/wallets/react-wallet-v2/src/components/PageHeader.tsx @@ -1,9 +1,15 @@ import { Text } from '@nextui-org/react' +/** + * Types + */ interface Props { children: string } +/** + * Component + */ export default function PageHeader({ children }: Props) { return ( { - actions.createWallet() - await actions.createWalletConnectClient() - actions.setInitialized() - }, [actions]) + walletActions.createWallet() + await walletActions.createWalletConnectClient() + walletActions.setInitialized() + }, [walletActions]) useEffect(() => { - if (!initialized) { + if (!waletReady) { onInitialize() } - }, [initialized, onInitialize]) + }, [waletReady, onInitialize]) return ( - {initialized ? ( + {waletReady ? ( Header diff --git a/wallets/react-wallet-v2/src/contexts/AccountContext.tsx b/wallets/react-wallet-v2/src/contexts/AccountContext.tsx new file mode 100644 index 0000000..e69de29 diff --git a/wallets/react-wallet-v2/src/contexts/WalletContext.tsx b/wallets/react-wallet-v2/src/contexts/WalletContext.tsx index 1553383..d13a8ef 100644 --- a/wallets/react-wallet-v2/src/contexts/WalletContext.tsx +++ b/wallets/react-wallet-v2/src/contexts/WalletContext.tsx @@ -7,7 +7,7 @@ import { createContext, ReactNode, useMemo, useState } from 'react' * Types */ interface State { - initialized: boolean + ready: boolean wallet: Wallet walletConnectClient: WalletConnectClient } @@ -19,8 +19,8 @@ interface Actions { } interface Context { - state: State - actions: Actions + walletState: State + walletActions: Actions } interface Props { @@ -33,13 +33,13 @@ interface Props { export const WalletContext = createContext({} as Context) export function WalletContextProvider({ children }: Props) { - const [state, setState] = useState({ - initialized: false, + const [walletState, setState] = useState({ + ready: false, wallet: undefined, walletConnectClient: undefined }) - const actions = useMemo( + const walletActions = useMemo( () => ({ setInitialized() { setState(s => ({ ...s, initialized: true })) @@ -70,5 +70,9 @@ export function WalletContextProvider({ children }: Props) { [] ) - return {children} + return ( + + {children} + + ) } From d2f77044335292fd331ddbfa6c9360207dc1c10a Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 4 Feb 2022 14:49:30 +0200 Subject: [PATCH 04/30] Replace context with valtio for easier readability --- wallets/react-wallet-v2/package.json | 3 +- .../src/containers/GlobalLayout.tsx | 26 +++---- .../src/contexts/AccountContext.tsx | 0 .../src/contexts/WalletContext.tsx | 78 ------------------- wallets/react-wallet-v2/src/pages/_app.tsx | 11 +-- .../react-wallet-v2/src/store/WalletStore.ts | 56 +++++++++++++ wallets/react-wallet-v2/yarn.lock | 12 +++ 7 files changed, 87 insertions(+), 99 deletions(-) delete mode 100644 wallets/react-wallet-v2/src/contexts/AccountContext.tsx delete mode 100644 wallets/react-wallet-v2/src/contexts/WalletContext.tsx create mode 100644 wallets/react-wallet-v2/src/store/WalletStore.ts diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 55c0e8a..842e0c9 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -16,7 +16,8 @@ "react": "17.0.2", "react-dom": "17.0.2", "ethers": "5.5.4", - "keyvaluestorage": "0.7.1" + "keyvaluestorage": "0.7.1", + "valtio": "1.2.11" }, "devDependencies": { "@walletconnect/types": "2.0.0-beta.22", diff --git a/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx b/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx index 3ec69e4..770f4fe 100644 --- a/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx +++ b/wallets/react-wallet-v2/src/containers/GlobalLayout.tsx @@ -1,6 +1,7 @@ -import { WalletContext } from '@/contexts/WalletContext' +import WalletStore from '@/store/WalletStore' import { Card, Container, Divider, Loading } from '@nextui-org/react' -import { Fragment, ReactNode, useCallback, useContext, useEffect } from 'react' +import { Fragment, ReactNode, useCallback, useEffect } from 'react' +import { useSnapshot } from 'valtio' /** * Types @@ -13,20 +14,19 @@ interface Props { * Container */ export default function GlobalLayout({ children }: Props) { - const { walletState, walletActions } = useContext(WalletContext) - const waletReady = walletState.ready + const { initialized } = useSnapshot(WalletStore.state) const onInitialize = useCallback(async () => { - walletActions.createWallet() - await walletActions.createWalletConnectClient() - walletActions.setInitialized() - }, [walletActions]) + WalletStore.createWallet() + await WalletStore.createWalletConnectClient() + WalletStore.setInitialized(true) + }, []) useEffect(() => { - if (!waletReady) { + if (!initialized) { onInitialize() } - }, [waletReady, onInitialize]) + }, [initialized, onInitialize]) return ( - {waletReady ? ( + {initialized ? ( Header diff --git a/wallets/react-wallet-v2/src/contexts/AccountContext.tsx b/wallets/react-wallet-v2/src/contexts/AccountContext.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/wallets/react-wallet-v2/src/contexts/WalletContext.tsx b/wallets/react-wallet-v2/src/contexts/WalletContext.tsx deleted file mode 100644 index d13a8ef..0000000 --- a/wallets/react-wallet-v2/src/contexts/WalletContext.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import WalletConnectClient from '@walletconnect/client' -import { Wallet } from 'ethers' -import KeyValueStorage from 'keyvaluestorage' -import { createContext, ReactNode, useMemo, useState } from 'react' - -/** - * Types - */ -interface State { - ready: boolean - wallet: Wallet - walletConnectClient: WalletConnectClient -} - -interface Actions { - setInitialized: () => void - createWallet: () => void - createWalletConnectClient: () => Promise -} - -interface Context { - walletState: State - walletActions: Actions -} - -interface Props { - children: ReactNode | ReactNode[] -} - -/** - * Context / Provider - */ -export const WalletContext = createContext({} as Context) - -export function WalletContextProvider({ children }: Props) { - const [walletState, setState] = useState({ - ready: false, - wallet: undefined, - walletConnectClient: undefined - }) - - const walletActions = useMemo( - () => ({ - setInitialized() { - setState(s => ({ ...s, initialized: true })) - }, - - createWallet() { - const wallet = Wallet.createRandom() - setState(s => ({ ...s, wallet })) - }, - - async createWalletConnectClient() { - const walletConnectClient = await WalletConnectClient.init({ - controller: true, - logger: 'debug', - projectId: '8f331b9812e0e5b8f2da2c7203624869', - relayUrl: 'wss://relay.walletconnect.com', - metadata: { - name: 'React Wallet', - description: 'React Wallet for WalletConnect', - url: 'https://walletconnect.com/', - icons: ['https://avatars.githubusercontent.com/u/37784886'] - }, - storage: new KeyValueStorage() - }) - setState(s => ({ ...s, walletConnectClient })) - } - }), - [] - ) - - return ( - - {children} - - ) -} diff --git a/wallets/react-wallet-v2/src/pages/_app.tsx b/wallets/react-wallet-v2/src/pages/_app.tsx index 5729b63..e297e12 100644 --- a/wallets/react-wallet-v2/src/pages/_app.tsx +++ b/wallets/react-wallet-v2/src/pages/_app.tsx @@ -1,16 +1,13 @@ -import Layout from '@/containers/GlobalLayout' -import { WalletContextProvider } from '@/contexts/WalletContext' +import GlobalLayout from '@/containers/GlobalLayout' import { NextUIProvider } from '@nextui-org/react' import { AppProps } from 'next/app' export default function App({ Component, pageProps }: AppProps) { return ( - - - - - + + + ) } diff --git a/wallets/react-wallet-v2/src/store/WalletStore.ts b/wallets/react-wallet-v2/src/store/WalletStore.ts new file mode 100644 index 0000000..0210af2 --- /dev/null +++ b/wallets/react-wallet-v2/src/store/WalletStore.ts @@ -0,0 +1,56 @@ +import WalletConnectClient from '@walletconnect/client' +import { Wallet } from 'ethers' +import KeyValueStorage from 'keyvaluestorage' +import { proxy } from 'valtio' + +/** + * Types + */ +interface State { + initialized: boolean + wallet: Wallet + walletConnectClient: WalletConnectClient +} + +/** + * State + */ +const state = proxy({ + initialized: false, + wallet: undefined, + walletConnectClient: undefined +}) + +/** + * Store / Actions + */ +const WalletStore = { + state, + + setInitialized(value: State['initialized']) { + state.initialized = value + }, + + createWallet() { + state.wallet = Wallet.createRandom() + }, + + async createWalletConnectClient() { + const walletConnectClient = await WalletConnectClient.init({ + controller: true, + logger: 'debug', + projectId: '8f331b9812e0e5b8f2da2c7203624869', + relayUrl: 'wss://relay.walletconnect.com', + metadata: { + name: 'React Wallet', + description: 'React Wallet for WalletConnect', + url: 'https://walletconnect.com/', + icons: ['https://avatars.githubusercontent.com/u/37784886'] + }, + storage: new KeyValueStorage() + }) + state.walletConnectClient = walletConnectClient + } +} + +export default WalletStore diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index 895b7e7..4d22ad2 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -2437,6 +2437,11 @@ prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.13.1" +proxy-compare@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/proxy-compare/-/proxy-compare-2.0.2.tgz#343e624d0ec399dfbe575f1d365d4fa042c9fc69" + integrity sha512-3qUXJBariEj3eO90M3Rgqq3+/P5Efl0t/dl9g/1uVzIQmO3M+ql4hvNH3mYdu8H+1zcKv07YvL55tsY74jmH1A== + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -2950,6 +2955,13 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +valtio@1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.2.11.tgz#1a49c6a24d774a1f0bb70692b20d93c1f7d40a06" + integrity sha512-zNbJsBNQ0EpzZnOUpuy6lUlpGSvkZu+/hZ9g7ifY3AQxo1RkqL7Ld6fVxRNLE04tVwOMNiDOgYihpEd6apLrog== + dependencies: + proxy-compare "2.0.2" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" From 9b0eff96b5bc6dbf46e04fcec9dae0b48662c140 Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 4 Feb 2022 15:02:46 +0200 Subject: [PATCH 05/30] Use next-themes for dark / light mode support --- wallets/react-wallet-v2/package.json | 1 + .../src/components/AccountCard.tsx | 3 +++ .../src/components/PageHeader.tsx | 2 +- wallets/react-wallet-v2/src/pages/_app.tsx | 21 ++++++++++++++----- wallets/react-wallet-v2/src/pages/index.tsx | 4 ++++ .../react-wallet-v2/src/utils/ThemeUtil.ts | 5 +++++ wallets/react-wallet-v2/yarn.lock | 5 +++++ 7 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 wallets/react-wallet-v2/src/components/AccountCard.tsx create mode 100644 wallets/react-wallet-v2/src/utils/ThemeUtil.ts diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 842e0c9..2243801 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -13,6 +13,7 @@ "@walletconnect/jsonrpc-utils": "1.0.0", "@nextui-org/react": "1.0.2-beta.3", "next": "12.0.10", + "next-themes": "0.0.15", "react": "17.0.2", "react-dom": "17.0.2", "ethers": "5.5.4", diff --git a/wallets/react-wallet-v2/src/components/AccountCard.tsx b/wallets/react-wallet-v2/src/components/AccountCard.tsx new file mode 100644 index 0000000..2d65672 --- /dev/null +++ b/wallets/react-wallet-v2/src/components/AccountCard.tsx @@ -0,0 +1,3 @@ +export default function AccountCard() { + return null +} diff --git a/wallets/react-wallet-v2/src/components/PageHeader.tsx b/wallets/react-wallet-v2/src/components/PageHeader.tsx index b187271..20cc0c7 100644 --- a/wallets/react-wallet-v2/src/components/PageHeader.tsx +++ b/wallets/react-wallet-v2/src/components/PageHeader.tsx @@ -15,7 +15,7 @@ export default function PageHeader({ children }: Props) { diff --git a/wallets/react-wallet-v2/src/pages/_app.tsx b/wallets/react-wallet-v2/src/pages/_app.tsx index e297e12..2c198cb 100644 --- a/wallets/react-wallet-v2/src/pages/_app.tsx +++ b/wallets/react-wallet-v2/src/pages/_app.tsx @@ -1,13 +1,24 @@ import GlobalLayout from '@/containers/GlobalLayout' +import { darkTheme, lightTheme } from '@/utils/ThemeUtil' import { NextUIProvider } from '@nextui-org/react' +import { ThemeProvider } from 'next-themes' import { AppProps } from 'next/app' export default function App({ Component, pageProps }: AppProps) { return ( - - - - - + + + + + + + ) } diff --git a/wallets/react-wallet-v2/src/pages/index.tsx b/wallets/react-wallet-v2/src/pages/index.tsx index 353310c..14dd0c6 100644 --- a/wallets/react-wallet-v2/src/pages/index.tsx +++ b/wallets/react-wallet-v2/src/pages/index.tsx @@ -1,5 +1,9 @@ import PageHeader from '@/components/PageHeader' +import WalletStore from '@/store/WalletStore' +import { useSnapshot } from 'valtio' export default function HomePage() { + const { wallet } = useSnapshot(WalletStore.state) + return Accounts } diff --git a/wallets/react-wallet-v2/src/utils/ThemeUtil.ts b/wallets/react-wallet-v2/src/utils/ThemeUtil.ts new file mode 100644 index 0000000..90045fa --- /dev/null +++ b/wallets/react-wallet-v2/src/utils/ThemeUtil.ts @@ -0,0 +1,5 @@ +import { createTheme } from '@nextui-org/react' + +export const darkTheme = createTheme({ type: 'dark' }) + +export const lightTheme = createTheme({ type: 'light' }) diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index 4d22ad2..e07af22 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -2159,6 +2159,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +next-themes@0.0.15: + version "0.0.15" + resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.15.tgz#ab0cee69cd763b77d41211f631e108beab39bf7d" + integrity sha512-LTmtqYi03c4gMTJmWwVK9XkHL7h0/+XrtR970Ujvtu3s0kZNeJN24aJsi4rkZOI8i19+qq6f8j+8Duwy5jqcrQ== + next@12.0.10: version "12.0.10" resolved "https://registry.yarnpkg.com/next/-/next-12.0.10.tgz#fcc4584177418bd777ce157f3165b7ba5e7708f7" From b79d0c533bd13427e4ae5f8c278b1c07d62747fe Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 4 Feb 2022 16:31:23 +0200 Subject: [PATCH 06/30] Account card component and helper utils --- wallets/react-wallet-v2/package.json | 2 +- .../src/components/AccountCard.tsx | 41 ++++++++++++++++++- .../src/components/PageHeader.tsx | 9 ++-- .../src/containers/GlobalLayout.tsx | 2 +- wallets/react-wallet-v2/src/pages/index.tsx | 12 +++++- .../react-wallet-v2/src/store/WalletStore.ts | 4 +- .../src/utils/EIP155ChainsUtil.ts | 34 +++++++++++++++ .../react-wallet-v2/src/utils/HelperUtil.ts | 12 ++++++ wallets/react-wallet-v2/yarn.lock | 7 +++- 9 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 wallets/react-wallet-v2/src/utils/EIP155ChainsUtil.ts create mode 100644 wallets/react-wallet-v2/src/utils/HelperUtil.ts diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 2243801..5d6329f 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -16,8 +16,8 @@ "next-themes": "0.0.15", "react": "17.0.2", "react-dom": "17.0.2", + "react-iconly": "2.2.5", "ethers": "5.5.4", - "keyvaluestorage": "0.7.1", "valtio": "1.2.11" }, "devDependencies": { diff --git a/wallets/react-wallet-v2/src/components/AccountCard.tsx b/wallets/react-wallet-v2/src/components/AccountCard.tsx index 2d65672..8904d08 100644 --- a/wallets/react-wallet-v2/src/components/AccountCard.tsx +++ b/wallets/react-wallet-v2/src/components/AccountCard.tsx @@ -1,3 +1,40 @@ -export default function AccountCard() { - return null +import { truncate } from '@/utils/HelperUtil' +import { Avatar, Button, Card, Text } from '@nextui-org/react' +import { Paper } from 'react-iconly' + +interface Props { + name: string + logo: string + rgb: string + address: string +} + +export default function AccountCard({ name, logo, rgb, address }: Props) { + return ( + + + +
+ + {name} + + + {truncate(address, 19)} + +
+ + } + /> +
+ ) +} diff --git a/wallets/react-wallet-v2/src/store/WalletConnectStore.ts b/wallets/react-wallet-v2/src/store/WalletConnectStore.ts deleted file mode 100644 index 47110c0..0000000 --- a/wallets/react-wallet-v2/src/store/WalletConnectStore.ts +++ /dev/null @@ -1,41 +0,0 @@ -import WalletConnectClient from '@walletconnect/client' -import { proxy } from 'valtio' - -/** - * Types - */ -interface State { - client: WalletConnectClient -} - -/** - * State - */ -const state = proxy({ - client: undefined -}) - -/** - * Store / Actions - */ -const WalletConnectStore = { - state, - - async createWalletConnectClient() { - const client = await WalletConnectClient.init({ - controller: true, - logger: 'debug', - projectId: '8f331b9812e0e5b8f2da2c7203624869', - relayUrl: 'wss://relay.walletconnect.com', - metadata: { - name: 'React Wallet', - description: 'React Wallet for WalletConnect', - url: 'https://walletconnect.com/', - icons: ['https://avatars.githubusercontent.com/u/37784886'] - } - }) - state.client = client - } -} - -export default WalletConnectStore diff --git a/wallets/react-wallet-v2/src/store/WalletStore.ts b/wallets/react-wallet-v2/src/store/WalletStore.ts index 4e1960c..f9cb799 100644 --- a/wallets/react-wallet-v2/src/store/WalletStore.ts +++ b/wallets/react-wallet-v2/src/store/WalletStore.ts @@ -5,7 +5,7 @@ import { proxy } from 'valtio' * Types */ interface State { - wallet: Wallet + wallet?: Wallet } /** diff --git a/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts b/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts new file mode 100644 index 0000000..6212035 --- /dev/null +++ b/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts @@ -0,0 +1,18 @@ +import WalletConnectClient from '@walletconnect/client' + +export let client: WalletConnectClient | undefined = undefined + +export async function createClient() { + client = await WalletConnectClient.init({ + controller: true, + logger: 'debug', + projectId: '8f331b9812e0e5b8f2da2c7203624869', + relayUrl: 'wss://relay.walletconnect.com', + metadata: { + name: 'React Wallet', + description: 'React Wallet for WalletConnect', + url: 'https://walletconnect.com/', + icons: ['https://avatars.githubusercontent.com/u/37784886'] + } + }) +} diff --git a/wallets/react-wallet-v2/tsconfig.json b/wallets/react-wallet-v2/tsconfig.json index 3806705..a9d5577 100644 --- a/wallets/react-wallet-v2/tsconfig.json +++ b/wallets/react-wallet-v2/tsconfig.json @@ -8,7 +8,7 @@ ], "allowJs": true, "skipLibCheck": true, - "strict": false, + "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "incremental": true, From 35947268a06e2c6d54f2cc25432ed217a2c25fd7 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 7 Feb 2022 15:34:36 +0200 Subject: [PATCH 11/30] Create modal component and store --- .../react-wallet-v2/src/components/Modal.tsx | 15 +++++++++ wallets/react-wallet-v2/src/pages/_app.tsx | 3 ++ .../react-wallet-v2/src/store/ModalStore.ts | 32 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 wallets/react-wallet-v2/src/components/Modal.tsx create mode 100644 wallets/react-wallet-v2/src/store/ModalStore.ts diff --git a/wallets/react-wallet-v2/src/components/Modal.tsx b/wallets/react-wallet-v2/src/components/Modal.tsx new file mode 100644 index 0000000..9769432 --- /dev/null +++ b/wallets/react-wallet-v2/src/components/Modal.tsx @@ -0,0 +1,15 @@ +import ModalStore from '@/store/ModalStore' +import { Modal as NextModal } from '@nextui-org/react' +import { useSnapshot } from 'valtio' + +export default function Modal() { + const { open } = useSnapshot(ModalStore.state) + + return ( + + + + + + ) +} diff --git a/wallets/react-wallet-v2/src/pages/_app.tsx b/wallets/react-wallet-v2/src/pages/_app.tsx index 921b993..20581a7 100644 --- a/wallets/react-wallet-v2/src/pages/_app.tsx +++ b/wallets/react-wallet-v2/src/pages/_app.tsx @@ -1,4 +1,5 @@ import Layout from '@/components/Layout' +import Modal from '@/components/Modal' import useInitialization from '@/hooks/useInitialization' import useWalletConnectEventsManager from '@/hooks/useWalletConnectEventsManager' import { darkTheme, lightTheme } from '@/utils/ThemeUtil' @@ -26,6 +27,8 @@ export default function App({ Component, pageProps }: AppProps) { + +
) diff --git a/wallets/react-wallet-v2/src/store/ModalStore.ts b/wallets/react-wallet-v2/src/store/ModalStore.ts new file mode 100644 index 0000000..da0a18c --- /dev/null +++ b/wallets/react-wallet-v2/src/store/ModalStore.ts @@ -0,0 +1,32 @@ +import { proxy } from 'valtio' + +/** + * Types + */ +interface State { + open: boolean +} + +/** + * State + */ +const state = proxy({ + open: false +}) + +/** + * Store / Actions + */ +const ModalStore = { + state, + + open() { + state.open = true + }, + + close() { + state.open = false + } +} + +export default ModalStore From 364661955a3391311a535b1b63c74fee07b3d223 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 8 Feb 2022 16:07:19 +0200 Subject: [PATCH 12/30] Nav menu --- wallets/react-wallet-v2/package.json | 4 +- .../react-wallet-v2/public/accounts-icon.svg | 24 ++++++++++ .../react-wallet-v2/public/settings-icon.svg | 9 ++++ .../public/wallet-connect-logo.svg | 3 ++ .../src/components/AccountCard.tsx | 15 ++++--- .../react-wallet-v2/src/components/Layout.tsx | 44 ++++++++++++++----- .../src/components/Navigation.tsx | 39 ++++++++++++++++ wallets/react-wallet-v2/yarn.lock | 8 ++-- 8 files changed, 123 insertions(+), 23 deletions(-) create mode 100644 wallets/react-wallet-v2/public/accounts-icon.svg create mode 100644 wallets/react-wallet-v2/public/settings-icon.svg create mode 100644 wallets/react-wallet-v2/public/wallet-connect-logo.svg create mode 100644 wallets/react-wallet-v2/src/components/Navigation.tsx diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 885debd..c5bbab4 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -2,7 +2,7 @@ "name": "react-wallet-v2", "private": true, "scripts": { - "dev": "next dev -p 3100", + "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" @@ -22,7 +22,7 @@ }, "devDependencies": { "@walletconnect/types": "2.0.0-beta.22", - "@types/node": "17.0.15", + "@types/node": "17.0.16", "@types/react": "17.0.39", "eslint": "8.8.0", "eslint-config-next": "12.0.10", diff --git a/wallets/react-wallet-v2/public/accounts-icon.svg b/wallets/react-wallet-v2/public/accounts-icon.svg new file mode 100644 index 0000000..c159f8f --- /dev/null +++ b/wallets/react-wallet-v2/public/accounts-icon.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wallets/react-wallet-v2/public/settings-icon.svg b/wallets/react-wallet-v2/public/settings-icon.svg new file mode 100644 index 0000000..11874aa --- /dev/null +++ b/wallets/react-wallet-v2/public/settings-icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/wallets/react-wallet-v2/public/wallet-connect-logo.svg b/wallets/react-wallet-v2/public/wallet-connect-logo.svg new file mode 100644 index 0000000..897281f --- /dev/null +++ b/wallets/react-wallet-v2/public/wallet-connect-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/wallets/react-wallet-v2/src/components/AccountCard.tsx b/wallets/react-wallet-v2/src/components/AccountCard.tsx index fca0044..0350aff 100644 --- a/wallets/react-wallet-v2/src/components/AccountCard.tsx +++ b/wallets/react-wallet-v2/src/components/AccountCard.tsx @@ -1,6 +1,5 @@ import { truncate } from '@/utils/HelperUtil' -import { Avatar, Button, Card, Text } from '@nextui-org/react' -import { Paper } from 'react-iconly' +import { Avatar, Card, Text } from '@nextui-org/react' interface Props { name: string @@ -16,14 +15,19 @@ export default function AccountCard({ name, logo, rgb, address }: Props) { borderWeight="light" css={{ borderColor: `rgba(${rgb}, 0.4)`, - boxShadow: `0 0 10px 0 rgba(${rgb}, 0.2)`, + boxShadow: `0 0 10px 0 rgba(${rgb}, 0.15)`, + backgroundColor: `rgba(${rgb}, 0.25)`, marginBottom: '$6', - overflowY: 'hidden', minHeight: '70px' }} >
@@ -34,7 +38,6 @@ export default function AccountCard({ name, logo, rgb, address }: Props) { {truncate(address, 19)}
- + + )} + + ) +} diff --git a/wallets/react-wallet-v2/src/components/QrReader/styles.module.css b/wallets/react-wallet-v2/src/components/QrReader/styles.module.css new file mode 100644 index 0000000..5e9225f --- /dev/null +++ b/wallets/react-wallet-v2/src/components/QrReader/styles.module.css @@ -0,0 +1,25 @@ +.container { + display: flex; + flex: 1; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.mask { + width: 100%; + border-radius: 15px; + overflow: hidden; + position: relative; +} + +.placeholder { + border: 2px rgba(139, 139, 139, 0.4) dashed; + width: 100%; + border-radius: 15px; + padding: 50px; +} + +.icon { + opacity: 0.3; +} \ No newline at end of file diff --git a/wallets/react-wallet-v2/src/pages/walletconnect.tsx b/wallets/react-wallet-v2/src/pages/walletconnect.tsx index 862d973..a17dab5 100644 --- a/wallets/react-wallet-v2/src/pages/walletconnect.tsx +++ b/wallets/react-wallet-v2/src/pages/walletconnect.tsx @@ -1,13 +1,14 @@ import PageHeader from '@/components/PageHeader' +import QrReader from '@/components/QrReader' import { client } from '@/utils/WalletConnectUtil' -import { Button, Input, Loading } from '@nextui-org/react' +import { Button, Input, Loading, Text } from '@nextui-org/react' import { Fragment, useState } from 'react' export default function WalletConnectPage() { const [uri, setUri] = useState('') const [loading, setLoading] = useState(false) - async function onConnect() { + async function onConnect(uri: string) { try { setLoading(true) await client?.pair({ uri }) @@ -21,14 +22,26 @@ export default function WalletConnectPage() { return ( WalletConnect + + + + + or use walletconnect uri + + setUri(e.target.value)} value={uri} contentRight={ - } diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index 54f3bc9..b97a525 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -1994,6 +1994,11 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +jsqr-es6@^1.4.0-1: + version "1.4.0-1" + resolved "https://registry.yarnpkg.com/jsqr-es6/-/jsqr-es6-1.4.0-1.tgz#e72d94a0ed794c6f19d87682ac89fab2a0f8496b" + integrity sha512-LPWZJLI+3LLOy9k3/s/MeXlkfNOs3bYBX5O+fp4N0XuxbgO8H7Uc/nYZeNwo13nSZXRW9xWFKmZdy9591+PyAg== + "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" @@ -2506,16 +2511,19 @@ react-dom@17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" -react-iconly@2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/react-iconly/-/react-iconly-2.2.5.tgz#32b9a1d66815ae6a421026694e7d16027248d87f" - integrity sha512-c9WO/2TJltmyCVGj+/mdJZFoldfzYA8uUPmcml03D6YlBVWsCN5gq5Vb2k95qmeg+vSqMRvC69yghZvM0T4lKQ== - react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-qr-reader-es6@2.2.1-2: + version "2.2.1-2" + resolved "https://registry.yarnpkg.com/react-qr-reader-es6/-/react-qr-reader-es6-2.2.1-2.tgz#d1e23881db4775e57ea82a8a7719d5e9d34879fe" + integrity sha512-pDNH8FoR3fOBBCgh4ImKHlX+pv/D3P8JmE+vjjcw3+YTEUgBqUAZbIkD/WUE3HzhVhN2zx7ZLBhO9vJngnjJxw== + dependencies: + jsqr-es6 "^1.4.0-1" + prop-types "^15.7.2" + react@17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -2965,10 +2973,10 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -valtio@1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.2.11.tgz#1a49c6a24d774a1f0bb70692b20d93c1f7d40a06" - integrity sha512-zNbJsBNQ0EpzZnOUpuy6lUlpGSvkZu+/hZ9g7ifY3AQxo1RkqL7Ld6fVxRNLE04tVwOMNiDOgYihpEd6apLrog== +valtio@1.2.12: + version "1.2.12" + resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.2.12.tgz#14f46f6c90b63c6e4176831c68ab9b729fea38ee" + integrity sha512-TlQkbSma4aAAgs6tQXrvGilMZBVH0q8gbbWxRbo2R43FhkW4lWi45f9jC6gAdJdC40bsNnYyBsYDB9OOKNlqSw== dependencies: proxy-compare "2.0.2" From fb6f484159437cd5fed5dafaafb4eb9b40f2cedb Mon Sep 17 00:00:00 2001 From: Ilja Date: Wed, 9 Feb 2022 15:05:11 +0200 Subject: [PATCH 14/30] route transitions, safari adjustments --- wallets/react-wallet-v2/package.json | 1 + .../react-wallet-v2/src/components/Layout.tsx | 24 ++++---- .../{QrReader/index.tsx => QrReader.tsx} | 9 ++- .../src/components/RouteTransition.tsx | 32 ++++++++++ wallets/react-wallet-v2/src/pages/_app.tsx | 5 +- .../styles.module.css => styles/main.css} | 17 ++++-- wallets/react-wallet-v2/yarn.lock | 60 +++++++++++++++++++ 7 files changed, 127 insertions(+), 21 deletions(-) rename wallets/react-wallet-v2/src/components/{QrReader/index.tsx => QrReader.tsx} (89%) create mode 100644 wallets/react-wallet-v2/src/components/RouteTransition.tsx rename wallets/react-wallet-v2/src/{components/QrReader/styles.module.css => styles/main.css} (60%) diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 15ac2ce..8568e32 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -17,6 +17,7 @@ "react": "17.0.2", "react-dom": "17.0.2", "react-qr-reader-es6": "2.2.1-2", + "framer-motion": "6.2.4", "ethers": "5.5.4", "valtio": "1.2.12" }, diff --git a/wallets/react-wallet-v2/src/components/Layout.tsx b/wallets/react-wallet-v2/src/components/Layout.tsx index 4ba859c..5ce99bd 100644 --- a/wallets/react-wallet-v2/src/components/Layout.tsx +++ b/wallets/react-wallet-v2/src/components/Layout.tsx @@ -1,4 +1,5 @@ import Navigation from '@/components/Navigation' +import RouteTransition from '@/components/RouteTransition' import { Card, Container, Loading } from '@nextui-org/react' import { Fragment, ReactNode } from 'react' @@ -35,6 +36,7 @@ export default function Layout({ children, initialized }: Props) { justifyContent: initialized ? 'normal' : 'center', alignItems: initialized ? 'normal' : 'center', borderRadius: 0, + outline: 'none', '@xs': { borderRadius: '$lg', height: '93vh', @@ -44,16 +46,18 @@ export default function Layout({ children, initialized }: Props) { > {initialized ? ( - - {children} - + + + {children} + + diff --git a/wallets/react-wallet-v2/src/components/QrReader/index.tsx b/wallets/react-wallet-v2/src/components/QrReader.tsx similarity index 89% rename from wallets/react-wallet-v2/src/components/QrReader/index.tsx rename to wallets/react-wallet-v2/src/components/QrReader.tsx index a68a72b..cfb07f2 100644 --- a/wallets/react-wallet-v2/src/components/QrReader/index.tsx +++ b/wallets/react-wallet-v2/src/components/QrReader.tsx @@ -2,7 +2,6 @@ import { Button, Loading } from '@nextui-org/react' import dynamic from 'next/dynamic' import Image from 'next/image' import { Fragment, useState } from 'react' -import s from './styles.module.css' /** * You can use normal import if you are not within next / ssr environment @@ -41,11 +40,11 @@ export default function QrReader({ onConnect }: IProps) { } return ( -
+
{show ? ( {loading && } -
+
setLoading(false)} showViewFinder={false} @@ -56,13 +55,13 @@ export default function QrReader({ onConnect }: IProps) {
) : ( -
+
qr code icon + + + + ) +} From eb063aca3a62a05b1d2f5670e221b26bf6cc4438 Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 11 Feb 2022 13:48:04 +0200 Subject: [PATCH 20/30] session.request modal flow --- wallets/react-wallet-v2/package.json | 6 +- .../react-wallet-v2/src/components/Modal.tsx | 4 +- .../hooks/useWalletConnectEventsManager.ts | 13 ++- .../react-wallet-v2/src/store/ModalStore.ts | 8 +- .../src/views/SessionRequestModal.tsx | 82 ++++++++++++++ wallets/react-wallet-v2/yarn.lock | 107 ++++++++++++++++-- 6 files changed, 196 insertions(+), 24 deletions(-) create mode 100644 wallets/react-wallet-v2/src/views/SessionRequestModal.tsx diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 8568e32..749fdd5 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -11,19 +11,19 @@ "@walletconnect/client": "2.0.0-beta.22", "@walletconnect/utils": "2.0.0-beta.22", "@walletconnect/jsonrpc-utils": "1.0.0", - "@nextui-org/react": "1.0.2-beta.3", + "@nextui-org/react": "1.0.2-beta.4", "next": "12.0.10", "next-themes": "0.0.15", "react": "17.0.2", "react-dom": "17.0.2", "react-qr-reader-es6": "2.2.1-2", - "framer-motion": "6.2.4", + "framer-motion": "6.2.6", "ethers": "5.5.4", "valtio": "1.2.12" }, "devDependencies": { "@walletconnect/types": "2.0.0-beta.22", - "@types/node": "17.0.16", + "@types/node": "17.0.17", "@types/react": "17.0.39", "eslint": "8.8.0", "eslint-config-next": "12.0.10", diff --git a/wallets/react-wallet-v2/src/components/Modal.tsx b/wallets/react-wallet-v2/src/components/Modal.tsx index 81f489e..52e5239 100644 --- a/wallets/react-wallet-v2/src/components/Modal.tsx +++ b/wallets/react-wallet-v2/src/components/Modal.tsx @@ -1,16 +1,16 @@ import ModalStore from '@/store/ModalStore' import SessionProposalModal from '@/views/SessionProposalModal' +import SessionRequestModal from '@/views/SessionRequestModal' import { Modal as NextModal } from '@nextui-org/react' import { useSnapshot } from 'valtio' export default function Modal() { const { open, view } = useSnapshot(ModalStore.state) - console.log(open) - return ( {view === 'SessionProposalModal' && } + {view === 'SessionRequestModal' && } ) } diff --git a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts index 22d720d..8391f77 100644 --- a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts +++ b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts @@ -6,12 +6,16 @@ import { useCallback, useEffect } from 'react' export default function useWalletConnectEventsManager(initialized: boolean) { const onSessionProposal = useCallback((proposal: SessionTypes.Proposal) => { - console.log(proposal) ModalStore.open('SessionProposalModal', { proposal }) }, []) const onSessionCreated = useCallback((created: SessionTypes.Created) => { - // ModalStore.open('SessionCreatedModal', { created }) + // TODO show successful feedback here + }, []) + + const onSessionRequest = useCallback(async (request: SessionTypes.RequestEvent) => { + const requestSession = await client?.session.get(request.topic) + ModalStore.open('SessionRequestModal', { request, requestSession }) }, []) useEffect(() => { @@ -21,6 +25,9 @@ export default function useWalletConnectEventsManager(initialized: boolean) { // 2. Open session created modal to show success feedback client.on(CLIENT_EVENTS.session.created, onSessionCreated) + + // 3. Open rpc request handling modal + client.on(CLIENT_EVENTS.session.request, onSessionRequest) } - }, [initialized, onSessionProposal, onSessionCreated]) + }, [initialized, onSessionProposal, onSessionCreated, onSessionRequest]) } diff --git a/wallets/react-wallet-v2/src/store/ModalStore.ts b/wallets/react-wallet-v2/src/store/ModalStore.ts index 2293b49..789269d 100644 --- a/wallets/react-wallet-v2/src/store/ModalStore.ts +++ b/wallets/react-wallet-v2/src/store/ModalStore.ts @@ -7,11 +7,13 @@ import { proxy } from 'valtio' interface ModalData { proposal?: SessionTypes.Proposal created?: SessionTypes.Created + request?: SessionTypes.RequestEvent + requestSession?: SessionTypes.Settled } interface State { open: boolean - view?: 'SessionProposalModal' | 'SessionCreatedModal' + view?: 'SessionProposalModal' | 'SessionRequestModal' data?: ModalData } @@ -19,9 +21,7 @@ interface State { * State */ const state = proxy({ - view: undefined, - open: false, - data: undefined + open: false }) /** diff --git a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx b/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx new file mode 100644 index 0000000..ddf411f --- /dev/null +++ b/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx @@ -0,0 +1,82 @@ +import ModalStore from '@/store/ModalStore' +import { CHAIN, MAINNET_CHAINS } from '@/utils/EIP155ChainsUtil' +import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' +import { Fragment } from 'react' + +export default function SessionRequestModal() { + const request = ModalStore.state.data?.request + const requestSession = ModalStore.state.data?.requestSession + + if (!request || !requestSession) { + return Missing request data + } + + const { + chainId, + request: { method } + } = request + const { protocol } = requestSession.relay + const { name, icons, url } = requestSession.peer.metadata + + async function onApprove() {} + + async function onReject() {} + + return ( + + + Request + + + + + + + + + + {name} + {url} + + + + + + + + Blockchain + {MAINNET_CHAINS[chainId as CHAIN]?.name ?? chainId} + + + + + + + + Method + {method} + + + + + + + + Relay Protocol + {protocol} + + + + + + + + + + + ) +} diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index 454ed1d..48026dc 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -24,6 +24,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.6.2": + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" + integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== + dependencies: + regenerator-runtime "^0.13.4" + "@emotion/is-prop-valid@^0.8.2": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" @@ -477,12 +484,16 @@ resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.0.10.tgz#5c0ba98b695c4be44d8793aff42971a0dac65c2d" integrity sha512-oUIWRKd24jFLRWUYO1CZmML5+32BcpVfqhimGaaZIXcOkfQW+iqiAzdqsv688zaGtyKGeB9ZtiK3NDf+Q0v+Vw== -"@nextui-org/react@1.0.2-beta.3": - version "1.0.2-beta.3" - resolved "https://registry.yarnpkg.com/@nextui-org/react/-/react-1.0.2-beta.3.tgz#d224654aa54a9b316922fdfacdd79d8ffa1d9797" - integrity sha512-YkAXBc4f3Qfzf409BFZi9MAKj0lWArTb1L2ZASAKoBQKsxtRbVTko18Losjsjun/WwK4X8RiR9e8XlzYPm2RZA== +"@nextui-org/react@1.0.2-beta.4": + version "1.0.2-beta.4" + resolved "https://registry.yarnpkg.com/@nextui-org/react/-/react-1.0.2-beta.4.tgz#fe88e4ed2335e0bf10dfb065474a5d1f66ba6766" + integrity sha512-14QFPOJwVn6c6WWmLyud/458DoVolWDBhq1wpMCe3o0dWdtNoOr/YwxiuZjSNwtypeDrroMbXcEIY4AoGzLV1w== dependencies: "@babel/runtime" "7.9.6" + "@react-aria/focus" "3.5.0" + "@react-aria/label" "3.2.1" + "@react-aria/ssr" "3.1.0" + "@react-aria/utils" "3.11.0" "@stitches/react" "1.2.6" "@nodelib/fs.scandir@2.1.5": @@ -506,6 +517,73 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@react-aria/focus@3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.5.0.tgz#02b85f97d6114af1eccc0902ce40723b626cb7f9" + integrity sha512-Eib75Q6QgQdn8VVVByg5Vipaaj/C//8Bs++sQY7nkomRx4sdArOnXbDppul3YHP6mRfU9VRLvAigEUlReQF/Xw== + dependencies: + "@babel/runtime" "^7.6.2" + "@react-aria/interactions" "^3.6.0" + "@react-aria/utils" "^3.9.0" + "@react-types/shared" "^3.9.0" + clsx "^1.1.1" + +"@react-aria/interactions@^3.6.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.7.0.tgz#eb19c1068b557a6b6df1e1c4abef07de719e9f25" + integrity sha512-Xomchjb9bqvh3ocil+QCEYFSxsTy8PHEz43mNP6z2yuu3UqTpl2FsWfyKgF/Yy0WKVkyV2dO2uz758KJTCLZhw== + dependencies: + "@babel/runtime" "^7.6.2" + "@react-aria/utils" "^3.10.0" + "@react-types/shared" "^3.10.0" + +"@react-aria/label@3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.2.1.tgz#e6562259e6b17e3856c4c3e0060903cf705d094b" + integrity sha512-QZ5/dpJKRjB1JtFZfOVd5GUiCpA2yMgmNA6ky6jT5XNAo7H14QqGRFUGDTLAQYGd+Bc3s+NayOT3NKUYur/3Xw== + dependencies: + "@babel/runtime" "^7.6.2" + "@react-aria/utils" "^3.10.0" + "@react-types/label" "^3.5.0" + "@react-types/shared" "^3.10.0" + +"@react-aria/ssr@3.1.0", "@react-aria/ssr@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.1.0.tgz#b7163e6224725c30121932a8d1422ef91d1fab22" + integrity sha512-RxqQKmE8sO7TGdrcSlHTcVzMP450hqowtBSd2bBS9oPlcokVkaGq28c3Rwa8ty5ctw4EBCjXqjP7xdcKMGDzug== + dependencies: + "@babel/runtime" "^7.6.2" + +"@react-aria/utils@3.11.0", "@react-aria/utils@^3.10.0", "@react-aria/utils@^3.9.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.11.0.tgz#215ea23a5435672a822cd713bdb8217972c5c80b" + integrity sha512-4yFA8E9xqDCUlolYSsoyp/qxrkiQrnEqx1BQOrKDuicpW7MBJ39pJC23YFMpyK2a6xEptc6xJEeIEFJXp57jJw== + dependencies: + "@babel/runtime" "^7.6.2" + "@react-aria/ssr" "^3.1.0" + "@react-stately/utils" "^3.3.0" + "@react-types/shared" "^3.10.1" + clsx "^1.1.1" + +"@react-stately/utils@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.3.0.tgz#99866c5788539268a06035acd5925b25bb4cedde" + integrity sha512-f//Y8q0+FFcS04xvCNvbba7WWRLHzj2AegLgdgwTxsnk9Gb+AyuasdRrRY7bGQhdHuEJ7OIiQZ9EQWndDbrTcg== + dependencies: + "@babel/runtime" "^7.6.2" + +"@react-types/label@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-types/label/-/label-3.5.0.tgz#c7093871f42c62e1b5523f61a0856a2f58d4cf2a" + integrity sha512-a9lpQUyV4XwsZv0gV1jPjPWicSSa+DRliuXLTwORirxNLF0kMk89DLYf0a9CZhiEniJYqoqR3laJDvLAFW1x/Q== + dependencies: + "@react-types/shared" "^3.9.0" + +"@react-types/shared@^3.10.0", "@react-types/shared@^3.10.1", "@react-types/shared@^3.9.0": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.10.1.tgz#16cd3038361dee63f351fa4d0fd25d90480a149b" + integrity sha512-U3dLJtstvOiZ8XLrWdNv9WXuruoDyfIfSXguTs9N0naDdO+M0MIbt/1Hg7Toe43ueAe56GM14IFL+S0/jhv8ow== + "@rushstack/eslint-patch@^1.0.8": version "1.1.0" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.0.tgz#7f698254aadf921e48dda8c0a6b304026b8a9323" @@ -567,10 +645,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/node@17.0.16": - version "17.0.16" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.16.tgz#e3733f46797b9df9e853ca9f719c8a6f7b84cd26" - integrity sha512-ydLaGVfQOQ6hI1xK2A5nVh8bl0OGoIfYMxPWHqqYe9bTkWCfqiVvZoh2I/QF2sNSkZzZyROBoTefIEI+PB6iIA== +"@types/node@17.0.17": + version "17.0.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.17.tgz#a8ddf6e0c2341718d74ee3dc413a13a042c45a0c" + integrity sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw== "@types/prop-types@*": version "15.7.4" @@ -1044,6 +1122,11 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -1614,10 +1697,10 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== -framer-motion@6.2.4: - version "6.2.4" - resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.2.4.tgz#3d9c61be3fb8381a770efccdb56cc421de662979" - integrity sha512-1UfnSG4c4CefKft6QMYGx8AWt3TtaFoR/Ax4dkuDDD5BDDeIuUm7gesmJrF8GzxeX/i6fMm8+MEdPngUyPVdLA== +framer-motion@6.2.6: + version "6.2.6" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.2.6.tgz#75277b4944a1234beaf7453da19028bbf4f75cce" + integrity sha512-7eGav5MxEEzDHozQTDY6+psTIOw2i2kM1QVoJOC3bCp9VOKoo+mKR5n7aT5JPh7ksEKFYJYz0GJDils/9S+oLA== dependencies: framesync "6.0.1" hey-listen "^1.0.8" From 4a95f9edbdbf41b019b49e8f8ee0f91e3d4b2b8b Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 11 Feb 2022 15:21:34 +0200 Subject: [PATCH 21/30] WIP on sign handling --- .../src/views/SessionProposalModal.tsx | 6 ++--- .../src/views/SessionRequestModal.tsx | 22 ++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx index 76ec238..8d778d0 100644 --- a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx @@ -10,12 +10,12 @@ export default function SessionProposalModal() { const proposal = ModalStore.state.data?.proposal const address = WalletStore.state.wallet?.address - // Ensure proposal and client are defined - if (!proposal || !client) { + // Ensure proposal is defined + if (!proposal) { return Missing proposal data } - // Get data to display + // Get required proposal data const { proposer, permissions, relay } = proposal const { icons, name, url } = proposer.metadata const { chains } = permissions.blockchain diff --git a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx b/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx index ddf411f..7b7f22e 100644 --- a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx @@ -1,25 +1,35 @@ import ModalStore from '@/store/ModalStore' +import WalletStore from '@/store/WalletStore' import { CHAIN, MAINNET_CHAINS } from '@/utils/EIP155ChainsUtil' +import { client } from '@/utils/WalletConnectUtil' import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' import { Fragment } from 'react' export default function SessionRequestModal() { + // Get request and wallet data from store const request = ModalStore.state.data?.request const requestSession = ModalStore.state.data?.requestSession + const { wallet } = WalletStore.state - if (!request || !requestSession) { + // Ensure request and wallet are defined + if (!request || !requestSession || !wallet) { return Missing request data } - const { - chainId, - request: { method } - } = request + // Get required request data + const { chainId } = request + const { method } = request.request const { protocol } = requestSession.relay const { name, icons, url } = requestSession.peer.metadata - async function onApprove() {} + // Handle approve action (logic varies based on request method) + async function onApprove() { + if (client && wallet) { + // TODO figure out how to sign different personal messages correctly with ethers + } + } + // Handle reject action async function onReject() {} return ( From de05b8c82cb63bb6642e5c17aa829c39c5c7e6bb Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 14 Feb 2022 12:10:44 +0200 Subject: [PATCH 22/30] Refactor wallet into util, restore from mnemonic, prep for session page --- wallets/react-wallet-v2/package.json | 4 +- .../src/components/AccountCard.tsx | 1 + .../EIP155Data.ts} | 23 +++++++- .../src/hooks/useInitialization.ts | 8 +-- .../hooks/useWalletConnectEventsManager.ts | 14 ++--- wallets/react-wallet-v2/src/pages/index.tsx | 11 +--- .../react-wallet-v2/src/pages/settings.tsx | 4 +- .../src/pages/walletconnect.tsx | 4 +- .../react-wallet-v2/src/store/WalletStore.ts | 29 --------- .../react-wallet-v2/src/utils/HelperUtil.ts | 14 +++++ .../src/utils/WalletConnectUtil.ts | 6 +- .../react-wallet-v2/src/utils/WalletUtil.ts | 17 ++++++ .../src/views/SessionProposalModal.tsx | 19 +++--- .../src/views/SessionRequestModal.tsx | 19 +++--- wallets/react-wallet-v2/yarn.lock | 59 ++++++++++--------- 15 files changed, 127 insertions(+), 105 deletions(-) rename wallets/react-wallet-v2/src/{utils/EIP155ChainsUtil.ts => data/EIP155Data.ts} (64%) delete mode 100644 wallets/react-wallet-v2/src/store/WalletStore.ts create mode 100644 wallets/react-wallet-v2/src/utils/WalletUtil.ts diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 749fdd5..edad553 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -19,13 +19,13 @@ "react-qr-reader-es6": "2.2.1-2", "framer-motion": "6.2.6", "ethers": "5.5.4", - "valtio": "1.2.12" + "valtio": "1.3.0" }, "devDependencies": { "@walletconnect/types": "2.0.0-beta.22", "@types/node": "17.0.17", "@types/react": "17.0.39", - "eslint": "8.8.0", + "eslint": "8.9.0", "eslint-config-next": "12.0.10", "eslint-config-prettier": "8.3.0", "prettier": "2.5.1", diff --git a/wallets/react-wallet-v2/src/components/AccountCard.tsx b/wallets/react-wallet-v2/src/components/AccountCard.tsx index 0350aff..fe57c11 100644 --- a/wallets/react-wallet-v2/src/components/AccountCard.tsx +++ b/wallets/react-wallet-v2/src/components/AccountCard.tsx @@ -12,6 +12,7 @@ export default function AccountCard({ name, logo, rgb, address }: Props) { return ( { try { - WalletStore.createWallet() - await createClient() + createOrRestoreWallet() + await createWalletConnectClient() setInitialized(true) } catch (err: unknown) { alert(err) diff --git a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts index 8391f77..fe6f9bd 100644 --- a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts +++ b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts @@ -1,5 +1,5 @@ import ModalStore from '@/store/ModalStore' -import { client } from '@/utils/WalletConnectUtil' +import { walletConnectClient } from '@/utils/WalletConnectUtil' import { CLIENT_EVENTS } from '@walletconnect/client' import { SessionTypes } from '@walletconnect/types' import { useCallback, useEffect } from 'react' @@ -10,24 +10,24 @@ export default function useWalletConnectEventsManager(initialized: boolean) { }, []) const onSessionCreated = useCallback((created: SessionTypes.Created) => { - // TODO show successful feedback here + // TODO show successful connection feedback here }, []) const onSessionRequest = useCallback(async (request: SessionTypes.RequestEvent) => { - const requestSession = await client?.session.get(request.topic) + const requestSession = await walletConnectClient.session.get(request.topic) ModalStore.open('SessionRequestModal', { request, requestSession }) }, []) useEffect(() => { - if (initialized && client) { + if (initialized) { // 1. Open session proposal modal for confirmation / rejection - client.on(CLIENT_EVENTS.session.proposal, onSessionProposal) + walletConnectClient.on(CLIENT_EVENTS.session.proposal, onSessionProposal) // 2. Open session created modal to show success feedback - client.on(CLIENT_EVENTS.session.created, onSessionCreated) + walletConnectClient.on(CLIENT_EVENTS.session.created, onSessionCreated) // 3. Open rpc request handling modal - client.on(CLIENT_EVENTS.session.request, onSessionRequest) + walletConnectClient.on(CLIENT_EVENTS.session.request, onSessionRequest) } }, [initialized, onSessionProposal, onSessionCreated, onSessionRequest]) } diff --git a/wallets/react-wallet-v2/src/pages/index.tsx b/wallets/react-wallet-v2/src/pages/index.tsx index b87ef28..ae54a27 100644 --- a/wallets/react-wallet-v2/src/pages/index.tsx +++ b/wallets/react-wallet-v2/src/pages/index.tsx @@ -1,17 +1,10 @@ import AccountCard from '@/components/AccountCard' import PageHeader from '@/components/PageHeader' -import WalletStore from '@/store/WalletStore' -import { MAINNET_CHAINS } from '@/utils/EIP155ChainsUtil' +import { MAINNET_CHAINS } from '@/data/EIP155Data' +import { wallet } from '@/utils/WalletUtil' import { Fragment } from 'react' -import { useSnapshot } from 'valtio' export default function HomePage() { - const { wallet } = useSnapshot(WalletStore.state) - - if (!wallet) { - return null - } - return ( Accounts diff --git a/wallets/react-wallet-v2/src/pages/settings.tsx b/wallets/react-wallet-v2/src/pages/settings.tsx index 1db5561..8f43dfd 100644 --- a/wallets/react-wallet-v2/src/pages/settings.tsx +++ b/wallets/react-wallet-v2/src/pages/settings.tsx @@ -1,5 +1,5 @@ import PageHeader from '@/components/PageHeader' -import WalletStore from '@/store/WalletStore' +import { wallet } from '@/utils/WalletUtil' import { Card, Divider, Row, Switch, Text } from '@nextui-org/react' import { Fragment } from 'react' @@ -11,7 +11,7 @@ export default function SettingsPage() { Mnemonic - {WalletStore.state.wallet?.mnemonic.phrase} + {wallet.mnemonic.phrase} diff --git a/wallets/react-wallet-v2/src/pages/walletconnect.tsx b/wallets/react-wallet-v2/src/pages/walletconnect.tsx index 7180319..8486c3c 100644 --- a/wallets/react-wallet-v2/src/pages/walletconnect.tsx +++ b/wallets/react-wallet-v2/src/pages/walletconnect.tsx @@ -1,6 +1,6 @@ import PageHeader from '@/components/PageHeader' import QrReader from '@/components/QrReader' -import { client } from '@/utils/WalletConnectUtil' +import { walletConnectClient } from '@/utils/WalletConnectUtil' import { Button, Input, Loading, Text } from '@nextui-org/react' import { Fragment, useState } from 'react' @@ -11,7 +11,7 @@ export default function WalletConnectPage() { async function onConnect(uri: string) { try { setLoading(true) - await client?.pair({ uri }) + await walletConnectClient.pair({ uri }) } catch (err: unknown) { alert(err) } finally { diff --git a/wallets/react-wallet-v2/src/store/WalletStore.ts b/wallets/react-wallet-v2/src/store/WalletStore.ts deleted file mode 100644 index f9cb799..0000000 --- a/wallets/react-wallet-v2/src/store/WalletStore.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Wallet } from 'ethers' -import { proxy } from 'valtio' - -/** - * Types - */ -interface State { - wallet?: Wallet -} - -/** - * State - */ -const state = proxy({ - wallet: undefined -}) - -/** - * Store / Actions - */ -const WalletStore = { - state, - - createWallet() { - state.wallet = Wallet.createRandom() - } -} - -export default WalletStore diff --git a/wallets/react-wallet-v2/src/utils/HelperUtil.ts b/wallets/react-wallet-v2/src/utils/HelperUtil.ts index c00c749..53f1d43 100644 --- a/wallets/react-wallet-v2/src/utils/HelperUtil.ts +++ b/wallets/react-wallet-v2/src/utils/HelperUtil.ts @@ -1,3 +1,6 @@ +/** + * Truncates string (in the middle) via given lenght value + */ export function truncate(value: string, length: number) { if (value.length <= length) { return value @@ -10,3 +13,14 @@ export function truncate(value: string, length: number) { return value.substring(0, frontLength) + separator + value.substring(value.length - backLength) } + +/** + * Helps to get message from various sign methods present in eth + * @details https://docs.metamask.io/guide/signing-data.html#a-brief-history + */ +export function getSignMessage(params: string[], walletAddress: string) { + // Remove our own address from params, so we are left with message + params.filter(p => p !== walletAddress) + + return params[0] +} diff --git a/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts b/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts index aaf43fa..6d1e75a 100644 --- a/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts +++ b/wallets/react-wallet-v2/src/utils/WalletConnectUtil.ts @@ -1,9 +1,9 @@ import WalletConnectClient from '@walletconnect/client' -export let client: WalletConnectClient | undefined = undefined +export let walletConnectClient: WalletConnectClient -export async function createClient() { - client = await WalletConnectClient.init({ +export async function createWalletConnectClient() { + walletConnectClient = await WalletConnectClient.init({ controller: true, projectId: '8f331b9812e0e5b8f2da2c7203624869', relayUrl: 'wss://relay.walletconnect.com', diff --git a/wallets/react-wallet-v2/src/utils/WalletUtil.ts b/wallets/react-wallet-v2/src/utils/WalletUtil.ts new file mode 100644 index 0000000..527a66c --- /dev/null +++ b/wallets/react-wallet-v2/src/utils/WalletUtil.ts @@ -0,0 +1,17 @@ +import { Wallet } from 'ethers' + +const STORAGE_KEY = 'WALLET_MNEMONIC' + +export let wallet: Wallet + +export function createOrRestoreWallet() { + const mnemonic = localStorage.getItem(STORAGE_KEY) + + if (mnemonic) { + wallet = Wallet.fromMnemonic(mnemonic) + } else { + wallet = Wallet.createRandom() + // Don't store mnemonic in local storage in a production project! + localStorage.setItem(STORAGE_KEY, wallet.mnemonic.phrase) + } +} diff --git a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx index 8d778d0..d4975b5 100644 --- a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx @@ -1,14 +1,13 @@ +import { MAINNET_CHAINS, TChain } from '@/data/EIP155Data' import ModalStore from '@/store/ModalStore' -import WalletStore from '@/store/WalletStore' -import { CHAIN, MAINNET_CHAINS } from '@/utils/EIP155ChainsUtil' -import { client } from '@/utils/WalletConnectUtil' +import { walletConnectClient } from '@/utils/WalletConnectUtil' +import { wallet } from '@/utils/WalletUtil' import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' import { Fragment } from 'react' export default function SessionProposalModal() { // Get proposal data and wallet address from store const proposal = ModalStore.state.data?.proposal - const address = WalletStore.state.wallet?.address // Ensure proposal is defined if (!proposal) { @@ -24,21 +23,21 @@ export default function SessionProposalModal() { // Hanlde approve action async function onApprove() { - if (client && proposal && address) { + if (proposal) { const response = { state: { - accounts: chains.map(chain => `${chain}:${address}`) + accounts: chains.map(chain => `${chain}:${wallet.address}`) } } - await client.approve({ proposal, response }) + await walletConnectClient.approve({ proposal, response }) } ModalStore.close() } // Hanlde reject action async function onReject() { - if (client && proposal) { - await client.reject({ proposal }) + if (proposal) { + await walletConnectClient.reject({ proposal }) } ModalStore.close() } @@ -67,7 +66,7 @@ export default function SessionProposalModal() { Blockchains - {chains.map(chain => MAINNET_CHAINS[chain as CHAIN]?.name ?? chain).join(', ')} + {chains.map(chain => MAINNET_CHAINS[chain as TChain]?.name ?? chain).join(', ')} diff --git a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx b/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx index 7b7f22e..93f3817 100644 --- a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx @@ -1,7 +1,7 @@ +import { MAINNET_CHAINS, TChain } from '@/data/EIP155Data' import ModalStore from '@/store/ModalStore' -import WalletStore from '@/store/WalletStore' -import { CHAIN, MAINNET_CHAINS } from '@/utils/EIP155ChainsUtil' -import { client } from '@/utils/WalletConnectUtil' +import { getSignMessage } from '@/utils/HelperUtil' +import { wallet } from '@/utils/WalletUtil' import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' import { Fragment } from 'react' @@ -9,23 +9,24 @@ export default function SessionRequestModal() { // Get request and wallet data from store const request = ModalStore.state.data?.request const requestSession = ModalStore.state.data?.requestSession - const { wallet } = WalletStore.state // Ensure request and wallet are defined - if (!request || !requestSession || !wallet) { + if (!request || !requestSession) { return Missing request data } // Get required request data const { chainId } = request - const { method } = request.request + const { method, params } = request.request const { protocol } = requestSession.relay const { name, icons, url } = requestSession.peer.metadata // Handle approve action (logic varies based on request method) async function onApprove() { - if (client && wallet) { - // TODO figure out how to sign different personal messages correctly with ethers + // Handle sign requests + if (['eth_sign', 'personal_sign'].includes(method)) { + const message = getSignMessage(params, wallet.address) + const signedMessage = wallet.signMessage(message) } } @@ -55,7 +56,7 @@ export default function SessionRequestModal() { Blockchain - {MAINNET_CHAINS[chainId as CHAIN]?.name ?? chainId} + {MAINNET_CHAINS[chainId as TChain]?.name ?? chainId} diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index 48026dc..3a96e5a 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -43,14 +43,14 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== -"@eslint/eslintrc@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318" - integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ== +"@eslint/eslintrc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.1.0.tgz#583d12dbec5d4f22f333f9669f7d0b7c7815b4d3" + integrity sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.2.0" + espree "^9.3.1" globals "^13.9.0" ignore "^4.0.6" import-fresh "^3.2.1" @@ -1465,10 +1465,10 @@ eslint-plugin-react@^7.27.0: semver "^6.3.0" string.prototype.matchall "^4.0.6" -eslint-scope@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153" - integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -1485,17 +1485,22 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2.0: +eslint-visitor-keys@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1" integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== -eslint@8.8.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.8.0.tgz#9762b49abad0cb4952539ffdb0a046392e571a2d" - integrity sha512-H3KXAzQGBH1plhYS3okDix2ZthuYJlQQEGE5k0IKuEqUSiyu4AmxxlJ2MtTYeJ3xB4jDhcYCwGOg2TXYdnDXlQ== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@8.9.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.9.0.tgz#a2a8227a99599adc4342fd9b854cb8d8d6412fdb" + integrity sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q== dependencies: - "@eslint/eslintrc" "^1.0.5" + "@eslint/eslintrc" "^1.1.0" "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" @@ -1503,10 +1508,10 @@ eslint@8.8.0: debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.0" + eslint-scope "^7.1.1" eslint-utils "^3.0.0" - eslint-visitor-keys "^3.2.0" - espree "^9.3.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1531,14 +1536,14 @@ eslint@8.8.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^9.2.0, espree@^9.3.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.0.tgz#c1240d79183b72aaee6ccfa5a90bc9111df085a8" - integrity sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ== +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== dependencies: acorn "^8.7.0" acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.1.0" + eslint-visitor-keys "^3.3.0" esquery@^1.4.0: version "1.4.0" @@ -3116,10 +3121,10 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -valtio@1.2.12: - version "1.2.12" - resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.2.12.tgz#14f46f6c90b63c6e4176831c68ab9b729fea38ee" - integrity sha512-TlQkbSma4aAAgs6tQXrvGilMZBVH0q8gbbWxRbo2R43FhkW4lWi45f9jC6gAdJdC40bsNnYyBsYDB9OOKNlqSw== +valtio@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.3.0.tgz#b83cfcca8455940119738659946565d5c0389af8" + integrity sha512-wsE6EDIkt+CNZPNHOxNVzoi026Fyt6ZRT750etZCAvrndcdT3N7Z+SSV4kJQdCwl5gNxsnU4BhP1wFS7cu21oA== dependencies: proxy-compare "2.0.2" From e2ac17957e211a19f415e4628cd2d18fd338f254 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 14 Feb 2022 15:38:09 +0200 Subject: [PATCH 23/30] Wrap up eth_sign and personal_sign examples --- wallets/react-wallet-v2/package.json | 3 +- .../{src/styles => public}/main.css | 0 .../src/components/AccountCard.tsx | 59 ++++++++++--------- .../react-wallet-v2/src/components/Modal.tsx | 4 +- .../react-wallet-v2/src/data/EIP155Data.ts | 27 +++++---- .../hooks/useWalletConnectEventsManager.ts | 22 ++++--- wallets/react-wallet-v2/src/pages/_app.tsx | 2 +- wallets/react-wallet-v2/src/pages/index.tsx | 4 +- .../react-wallet-v2/src/pages/sessions.tsx | 20 +++++++ .../react-wallet-v2/src/store/ModalStore.ts | 4 +- .../src/utils/RequestHandlerUtil.ts | 28 +++++++++ .../src/views/SessionProposalModal.tsx | 6 +- ...nRequestModal.tsx => SessionSignModal.tsx} | 57 ++++++++++++++---- wallets/react-wallet-v2/yarn.lock | 20 +++++++ 14 files changed, 183 insertions(+), 73 deletions(-) rename wallets/react-wallet-v2/{src/styles => public}/main.css (100%) create mode 100644 wallets/react-wallet-v2/src/pages/sessions.tsx create mode 100644 wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts rename wallets/react-wallet-v2/src/views/{SessionRequestModal.tsx => SessionSignModal.tsx} (56%) diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index edad553..48dbcdb 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -19,7 +19,8 @@ "react-qr-reader-es6": "2.2.1-2", "framer-motion": "6.2.6", "ethers": "5.5.4", - "valtio": "1.3.0" + "valtio": "1.3.0", + "@json-rpc-tools/utils": "1.7.6" }, "devDependencies": { "@walletconnect/types": "2.0.0-beta.22", diff --git a/wallets/react-wallet-v2/src/styles/main.css b/wallets/react-wallet-v2/public/main.css similarity index 100% rename from wallets/react-wallet-v2/src/styles/main.css rename to wallets/react-wallet-v2/public/main.css diff --git a/wallets/react-wallet-v2/src/components/AccountCard.tsx b/wallets/react-wallet-v2/src/components/AccountCard.tsx index fe57c11..fb6ff69 100644 --- a/wallets/react-wallet-v2/src/components/AccountCard.tsx +++ b/wallets/react-wallet-v2/src/components/AccountCard.tsx @@ -1,5 +1,6 @@ import { truncate } from '@/utils/HelperUtil' import { Avatar, Card, Text } from '@nextui-org/react' +import Link from 'next/link' interface Props { name: string @@ -10,36 +11,38 @@ interface Props { export default function AccountCard({ name, logo, rgb, address }: Props) { return ( - - + - -
- - {name} - - - {truncate(address, 19)} - -
-
-
+ + +
+ + {name} + + + {truncate(address, 19)} + +
+
+
+ ) } diff --git a/wallets/react-wallet-v2/src/components/Modal.tsx b/wallets/react-wallet-v2/src/components/Modal.tsx index 52e5239..29f6204 100644 --- a/wallets/react-wallet-v2/src/components/Modal.tsx +++ b/wallets/react-wallet-v2/src/components/Modal.tsx @@ -1,6 +1,6 @@ import ModalStore from '@/store/ModalStore' import SessionProposalModal from '@/views/SessionProposalModal' -import SessionRequestModal from '@/views/SessionRequestModal' +import SessionRequestModal from '@/views/SessionSignModal' import { Modal as NextModal } from '@nextui-org/react' import { useSnapshot } from 'valtio' @@ -10,7 +10,7 @@ export default function Modal() { return ( {view === 'SessionProposalModal' && } - {view === 'SessionRequestModal' && } + {view === 'SessionSignModal' && } ) } diff --git a/wallets/react-wallet-v2/src/data/EIP155Data.ts b/wallets/react-wallet-v2/src/data/EIP155Data.ts index 20672d8..efc5cee 100644 --- a/wallets/react-wallet-v2/src/data/EIP155Data.ts +++ b/wallets/react-wallet-v2/src/data/EIP155Data.ts @@ -3,20 +3,20 @@ * @url https://chainlist.org */ -/** - * Types - */ -export type TChain = keyof typeof MAINNET_CHAINS - /** * Utilities */ -export const LOGO_BASE_URL = 'https://blockchain-api.xyz/logos/' +const LOGO_BASE_URL = 'https://blockchain-api.xyz/logos/' + +/** + * Types + */ +export type TEIP155Chain = keyof typeof EIP155_CHAINS /** * Chains */ -export const MAINNET_CHAINS = { +export const EIP155_CHAINS = { 'eip155:1': { chainId: 1, name: 'Ethereum', @@ -46,11 +46,12 @@ export const MAINNET_CHAINS = { /** * Methods */ -export const SIGNING_METHODS = { +export const EIP155_SIGNING_METHODS = { PERSONAL_SIGN: 'personal_sign', - SEND_TRANSACTION: 'eth_sendTransaction', - SIGN: 'eth_sign', - SIGN_TRANSACTION: 'eth_signTransaction', - SIGN_TYPED_DATA: 'eth_signTypedData', - SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4' + ETH_SIGN: 'eth_sign', + ETH_SIGN_TRANSACTION: 'eth_signTransaction', + ETH_SIGN_TYPED_DATA: 'eth_signTypedData', + ETH_SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4', + ETH_SIGN_RAW_TRANSACTION: 'eth_sendRawTransaction', + ETH_SEND_TRANSACTION: 'eth_sendTransaction' } diff --git a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts index fe6f9bd..079ce4a 100644 --- a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts +++ b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts @@ -1,3 +1,4 @@ +import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data' import ModalStore from '@/store/ModalStore' import { walletConnectClient } from '@/utils/WalletConnectUtil' import { CLIENT_EVENTS } from '@walletconnect/client' @@ -5,28 +6,31 @@ import { SessionTypes } from '@walletconnect/types' import { useCallback, useEffect } from 'react' export default function useWalletConnectEventsManager(initialized: boolean) { + // 1. Open session proposal modal for confirmation / rejection const onSessionProposal = useCallback((proposal: SessionTypes.Proposal) => { ModalStore.open('SessionProposalModal', { proposal }) }, []) - const onSessionCreated = useCallback((created: SessionTypes.Created) => { - // TODO show successful connection feedback here - }, []) + // 2. Open session created modal to show success feedback + const onSessionCreated = useCallback((created: SessionTypes.Created) => {}, []) - const onSessionRequest = useCallback(async (request: SessionTypes.RequestEvent) => { - const requestSession = await walletConnectClient.session.get(request.topic) - ModalStore.open('SessionRequestModal', { request, requestSession }) + // 3. Open rpc request handling modal based on method that was used + const onSessionRequest = useCallback(async (requestEvent: SessionTypes.RequestEvent) => { + const { topic, request } = requestEvent + const { method } = request + const requestSession = await walletConnectClient.session.get(topic) + + if ([EIP155_SIGNING_METHODS.ETH_SIGN, EIP155_SIGNING_METHODS.PERSONAL_SIGN].includes(method)) { + ModalStore.open('SessionSignModal', { requestEvent, requestSession }) + } }, []) useEffect(() => { if (initialized) { - // 1. Open session proposal modal for confirmation / rejection walletConnectClient.on(CLIENT_EVENTS.session.proposal, onSessionProposal) - // 2. Open session created modal to show success feedback walletConnectClient.on(CLIENT_EVENTS.session.created, onSessionCreated) - // 3. Open rpc request handling modal walletConnectClient.on(CLIENT_EVENTS.session.request, onSessionRequest) } }, [initialized, onSessionProposal, onSessionCreated, onSessionRequest]) diff --git a/wallets/react-wallet-v2/src/pages/_app.tsx b/wallets/react-wallet-v2/src/pages/_app.tsx index 92fb4ce..a375bb2 100644 --- a/wallets/react-wallet-v2/src/pages/_app.tsx +++ b/wallets/react-wallet-v2/src/pages/_app.tsx @@ -2,11 +2,11 @@ import Layout from '@/components/Layout' import Modal from '@/components/Modal' import useInitialization from '@/hooks/useInitialization' import useWalletConnectEventsManager from '@/hooks/useWalletConnectEventsManager' -import '@/styles/main.css' import { darkTheme, lightTheme } from '@/utils/ThemeUtil' import { NextUIProvider } from '@nextui-org/react' import { ThemeProvider } from 'next-themes' import { AppProps } from 'next/app' +import '../../public/main.css' export default function App({ Component, pageProps }: AppProps) { // Step 1 - Initialize wallets and wallet connect client diff --git a/wallets/react-wallet-v2/src/pages/index.tsx b/wallets/react-wallet-v2/src/pages/index.tsx index ae54a27..a1014ff 100644 --- a/wallets/react-wallet-v2/src/pages/index.tsx +++ b/wallets/react-wallet-v2/src/pages/index.tsx @@ -1,6 +1,6 @@ import AccountCard from '@/components/AccountCard' import PageHeader from '@/components/PageHeader' -import { MAINNET_CHAINS } from '@/data/EIP155Data' +import { EIP155_CHAINS } from '@/data/EIP155Data' import { wallet } from '@/utils/WalletUtil' import { Fragment } from 'react' @@ -8,7 +8,7 @@ export default function HomePage() { return ( Accounts - {Object.values(MAINNET_CHAINS).map(({ name, logo, rgb }) => ( + {Object.values(EIP155_CHAINS).map(({ name, logo, rgb }) => ( ))} diff --git a/wallets/react-wallet-v2/src/pages/sessions.tsx b/wallets/react-wallet-v2/src/pages/sessions.tsx new file mode 100644 index 0000000..5b0e968 --- /dev/null +++ b/wallets/react-wallet-v2/src/pages/sessions.tsx @@ -0,0 +1,20 @@ +import PageHeader from '@/components/PageHeader' +import { truncate } from '@/utils/HelperUtil' +import { walletConnectClient } from '@/utils/WalletConnectUtil' +import { useRouter } from 'next/router' +import { Fragment, useEffect } from 'react' + +export default function SessionsPage() { + const { query } = useRouter() + const address = (query?.address as string) ?? 'Unknown' + + useEffect(() => { + console.log(walletConnectClient.session.values) + }, []) + + return ( + + {truncate(address, 15)} + + ) +} diff --git a/wallets/react-wallet-v2/src/store/ModalStore.ts b/wallets/react-wallet-v2/src/store/ModalStore.ts index 789269d..b46b454 100644 --- a/wallets/react-wallet-v2/src/store/ModalStore.ts +++ b/wallets/react-wallet-v2/src/store/ModalStore.ts @@ -7,13 +7,13 @@ import { proxy } from 'valtio' interface ModalData { proposal?: SessionTypes.Proposal created?: SessionTypes.Created - request?: SessionTypes.RequestEvent + requestEvent?: SessionTypes.RequestEvent requestSession?: SessionTypes.Settled } interface State { open: boolean - view?: 'SessionProposalModal' | 'SessionRequestModal' + view?: 'SessionProposalModal' | 'SessionSignModal' data?: ModalData } diff --git a/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts new file mode 100644 index 0000000..640fa7a --- /dev/null +++ b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts @@ -0,0 +1,28 @@ +import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data' +import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils' +import { RequestEvent } from '@walletconnect/types' +import { ERROR } from '@walletconnect/utils' +import { Wallet } from 'ethers' + +export async function approveEIP155Request(request: RequestEvent['request'], wallet: Wallet) { + const { method, params, id } = request + + switch (method) { + case EIP155_SIGNING_METHODS.PERSONAL_SIGN: + const personalSignResult = await wallet.signMessage(params[0]) + return formatJsonRpcResult(id, personalSignResult) + + case EIP155_SIGNING_METHODS.ETH_SIGN: + const ethSignResult = await wallet.signMessage(params[1]) + return formatJsonRpcResult(id, ethSignResult) + + default: + throw new Error(ERROR.UNKNOWN_JSONRPC_METHOD.format().message) + } +} + +export function rejectEIP155Request(request: RequestEvent['request']) { + const { id } = request + + return formatJsonRpcError(id, ERROR.JSONRPC_REQUEST_METHOD_REJECTED.format().message) +} diff --git a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx index d4975b5..2f9e13e 100644 --- a/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx @@ -1,4 +1,4 @@ -import { MAINNET_CHAINS, TChain } from '@/data/EIP155Data' +import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data' import ModalStore from '@/store/ModalStore' import { walletConnectClient } from '@/utils/WalletConnectUtil' import { wallet } from '@/utils/WalletUtil' @@ -66,7 +66,9 @@ export default function SessionProposalModal() { Blockchains - {chains.map(chain => MAINNET_CHAINS[chain as TChain]?.name ?? chain).join(', ')} + {chains + .map(chain => EIP155_CHAINS[chain as TEIP155Chain]?.name ?? chain) + .join(', ')} diff --git a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx b/wallets/react-wallet-v2/src/views/SessionSignModal.tsx similarity index 56% rename from wallets/react-wallet-v2/src/views/SessionRequestModal.tsx rename to wallets/react-wallet-v2/src/views/SessionSignModal.tsx index 93f3817..563e01c 100644 --- a/wallets/react-wallet-v2/src/views/SessionRequestModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionSignModal.tsx @@ -1,37 +1,57 @@ -import { MAINNET_CHAINS, TChain } from '@/data/EIP155Data' +import { EIP155_CHAINS, EIP155_SIGNING_METHODS, TEIP155Chain } from '@/data/EIP155Data' import ModalStore from '@/store/ModalStore' -import { getSignMessage } from '@/utils/HelperUtil' +import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil' +import { walletConnectClient } from '@/utils/WalletConnectUtil' import { wallet } from '@/utils/WalletUtil' import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' +import { utils } from 'ethers' import { Fragment } from 'react' -export default function SessionRequestModal() { +export default function SessionSignModal() { // Get request and wallet data from store - const request = ModalStore.state.data?.request + const requestEvent = ModalStore.state.data?.requestEvent const requestSession = ModalStore.state.data?.requestSession // Ensure request and wallet are defined - if (!request || !requestSession) { + if (!requestEvent || !requestSession) { return Missing request data } // Get required request data - const { chainId } = request - const { method, params } = request.request + const { chainId } = requestEvent + const { method, params } = requestEvent.request const { protocol } = requestSession.relay const { name, icons, url } = requestSession.peer.metadata + // Get message as utf string + let message = method === EIP155_SIGNING_METHODS.PERSONAL_SIGN ? params[0] : params[1] + if (utils.isHexString(message)) { + message = utils.toUtf8String(message) + } + // Handle approve action (logic varies based on request method) async function onApprove() { - // Handle sign requests - if (['eth_sign', 'personal_sign'].includes(method)) { - const message = getSignMessage(params, wallet.address) - const signedMessage = wallet.signMessage(message) + if (requestEvent) { + const response = await approveEIP155Request(requestEvent.request, wallet) + await walletConnectClient.respond({ + topic: requestEvent.topic, + response + }) + ModalStore.close() } } // Handle reject action - async function onReject() {} + async function onReject() { + if (requestEvent) { + const response = rejectEIP155Request(requestEvent.request) + await walletConnectClient.respond({ + topic: requestEvent.topic, + response + }) + ModalStore.close() + } + } return ( @@ -56,7 +76,18 @@ export default function SessionRequestModal() { Blockchain - {MAINNET_CHAINS[chainId as TChain]?.name ?? chainId} + + {EIP155_CHAINS[chainId as TEIP155Chain]?.name ?? chainId} + + + + + + + + + Message + {message} diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index 3a96e5a..439b972 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -417,6 +417,21 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@json-rpc-tools/types@^1.7.6": + version "1.7.6" + resolved "https://registry.yarnpkg.com/@json-rpc-tools/types/-/types-1.7.6.tgz#5abd5fde01364a130c46093b501715bcce5bdc0e" + integrity sha512-nDSqmyRNEqEK9TZHtM15uNnDljczhCUdBmRhpNZ95bIPKEDQ+nTDmGMFd2lLin3upc5h2VVVd9tkTDdbXUhDIQ== + dependencies: + keyvaluestorage-interface "^1.0.0" + +"@json-rpc-tools/utils@1.7.6": + version "1.7.6" + resolved "https://registry.yarnpkg.com/@json-rpc-tools/utils/-/utils-1.7.6.tgz#67f04987dbaa2e7adb6adff1575367b75a9a9ba1" + integrity sha512-HjA8x/U/Q78HRRe19yh8HVKoZ+Iaoo3YZjakJYxR+rw52NHo6jM+VE9b8+7ygkCFXl/EHID5wh/MkXaE/jGyYw== + dependencies: + "@json-rpc-tools/types" "^1.7.6" + "@pedrouid/environment" "^1.0.1" + "@next/env@12.0.10": version "12.0.10" resolved "https://registry.yarnpkg.com/@next/env/-/env-12.0.10.tgz#561640fd62279218ccd2798ae907bae8d94a7730" @@ -517,6 +532,11 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@pedrouid/environment@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@pedrouid/environment/-/environment-1.0.1.tgz#858f0f8a057340e0b250398b75ead77d6f4342ec" + integrity sha512-HaW78NszGzRZd9SeoI3JD11JqY+lubnaOx7Pewj5pfjqWXOEATpeKIFb9Z4t2WBUK2iryiXX3lzWwmYWgUL0Ug== + "@react-aria/focus@3.5.0": version "3.5.0" resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.5.0.tgz#02b85f97d6114af1eccc0902ce40723b626cb7f9" From 354cf0bf34c9231519e874c547a691990ec3b357 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 14 Feb 2022 15:46:11 +0200 Subject: [PATCH 24/30] Fix logic for personal_sign signing --- wallets/react-wallet-v2/src/utils/HelperUtil.ts | 14 ++++++++------ .../src/utils/RequestHandlerUtil.ts | 5 +++-- .../react-wallet-v2/src/views/SessionSignModal.tsx | 8 +++----- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/wallets/react-wallet-v2/src/utils/HelperUtil.ts b/wallets/react-wallet-v2/src/utils/HelperUtil.ts index 53f1d43..62c3567 100644 --- a/wallets/react-wallet-v2/src/utils/HelperUtil.ts +++ b/wallets/react-wallet-v2/src/utils/HelperUtil.ts @@ -1,3 +1,5 @@ +import { utils } from 'ethers' + /** * Truncates string (in the middle) via given lenght value */ @@ -15,12 +17,12 @@ export function truncate(value: string, length: number) { } /** - * Helps to get message from various sign methods present in eth - * @details https://docs.metamask.io/guide/signing-data.html#a-brief-history + * Converts hex to utf8 string if it is valid bytes */ -export function getSignMessage(params: string[], walletAddress: string) { - // Remove our own address from params, so we are left with message - params.filter(p => p !== walletAddress) +export function convertHexToUtf8(value: string) { + if (utils.isHexString(value)) { + return utils.toUtf8String(value) + } - return params[0] + return value } diff --git a/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts index 640fa7a..498e8b5 100644 --- a/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts +++ b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts @@ -1,4 +1,5 @@ import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data' +import { convertHexToUtf8 } from '@/utils/HelperUtil' import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils' import { RequestEvent } from '@walletconnect/types' import { ERROR } from '@walletconnect/utils' @@ -9,11 +10,11 @@ export async function approveEIP155Request(request: RequestEvent['request'], wal switch (method) { case EIP155_SIGNING_METHODS.PERSONAL_SIGN: - const personalSignResult = await wallet.signMessage(params[0]) + const personalSignResult = await wallet.signMessage(convertHexToUtf8(params[0])) return formatJsonRpcResult(id, personalSignResult) case EIP155_SIGNING_METHODS.ETH_SIGN: - const ethSignResult = await wallet.signMessage(params[1]) + const ethSignResult = await wallet.signMessage(convertHexToUtf8(params[1])) return formatJsonRpcResult(id, ethSignResult) default: diff --git a/wallets/react-wallet-v2/src/views/SessionSignModal.tsx b/wallets/react-wallet-v2/src/views/SessionSignModal.tsx index 563e01c..57a66c5 100644 --- a/wallets/react-wallet-v2/src/views/SessionSignModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionSignModal.tsx @@ -1,10 +1,10 @@ import { EIP155_CHAINS, EIP155_SIGNING_METHODS, TEIP155Chain } from '@/data/EIP155Data' import ModalStore from '@/store/ModalStore' +import { convertHexToUtf8 } from '@/utils/HelperUtil' import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil' import { walletConnectClient } from '@/utils/WalletConnectUtil' import { wallet } from '@/utils/WalletUtil' import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' -import { utils } from 'ethers' import { Fragment } from 'react' export default function SessionSignModal() { @@ -23,11 +23,9 @@ export default function SessionSignModal() { const { protocol } = requestSession.relay const { name, icons, url } = requestSession.peer.metadata - // Get message as utf string + // Get message, convert it to UTF8 string if it is valid hex let message = method === EIP155_SIGNING_METHODS.PERSONAL_SIGN ? params[0] : params[1] - if (utils.isHexString(message)) { - message = utils.toUtf8String(message) - } + message = convertHexToUtf8(message) // Handle approve action (logic varies based on request method) async function onApprove() { From 01c9d2d861760ff36113f9af3ebcd7abf27e7047 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 14 Feb 2022 15:51:49 +0200 Subject: [PATCH 25/30] Implement light and dark theme toggles --- .../src/hooks/useWalletConnectEventsManager.ts | 2 +- wallets/react-wallet-v2/src/pages/settings.tsx | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts index 079ce4a..d5497da 100644 --- a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts +++ b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts @@ -14,7 +14,7 @@ export default function useWalletConnectEventsManager(initialized: boolean) { // 2. Open session created modal to show success feedback const onSessionCreated = useCallback((created: SessionTypes.Created) => {}, []) - // 3. Open rpc request handling modal based on method that was used + // 3. Open request handling modal based on method that was used const onSessionRequest = useCallback(async (requestEvent: SessionTypes.RequestEvent) => { const { topic, request } = requestEvent const { method } = request diff --git a/wallets/react-wallet-v2/src/pages/settings.tsx b/wallets/react-wallet-v2/src/pages/settings.tsx index 8f43dfd..87de47c 100644 --- a/wallets/react-wallet-v2/src/pages/settings.tsx +++ b/wallets/react-wallet-v2/src/pages/settings.tsx @@ -1,9 +1,13 @@ import PageHeader from '@/components/PageHeader' import { wallet } from '@/utils/WalletUtil' -import { Card, Divider, Row, Switch, Text } from '@nextui-org/react' +import { Card, Divider, Row, Switch, Text, useTheme } from '@nextui-org/react' +import { useTheme as useNextTheme } from 'next-themes' import { Fragment } from 'react' export default function SettingsPage() { + const { setTheme } = useNextTheme() + const { isDark, type } = useTheme() + return ( Settings @@ -34,7 +38,8 @@ export default function SettingsPage() { Theme - Dark + setTheme(e.target.checked ? 'dark' : 'light')} />{' '} + {type} ) From 96d86505088ecb99e40a3fccddcee37e49c61754 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 15 Feb 2022 12:47:36 +0200 Subject: [PATCH 26/30] fix mobile scrolling --- wallets/react-wallet-v2/public/main.css | 8 ------ .../react-wallet-v2/src/data/EIP155Data.ts | 27 ++++++++++++++++++ .../react-wallet-v2/src/pages/settings.tsx | 8 ++++-- .../src/store/SettingsStore.ts | 28 +++++++++++++++++++ 4 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 wallets/react-wallet-v2/src/store/SettingsStore.ts diff --git a/wallets/react-wallet-v2/public/main.css b/wallets/react-wallet-v2/public/main.css index ab997f5..3615e4a 100644 --- a/wallets/react-wallet-v2/public/main.css +++ b/wallets/react-wallet-v2/public/main.css @@ -2,14 +2,6 @@ box-sizing: border-box; } -body, -html { - position: fixed; - height: 100vh; - width: 100vw; - overflow: hidden; -} - .routeTransition { width: 100%; height: 100%; diff --git a/wallets/react-wallet-v2/src/data/EIP155Data.ts b/wallets/react-wallet-v2/src/data/EIP155Data.ts index efc5cee..c9ecf2d 100644 --- a/wallets/react-wallet-v2/src/data/EIP155Data.ts +++ b/wallets/react-wallet-v2/src/data/EIP155Data.ts @@ -43,6 +43,33 @@ export const EIP155_CHAINS = { } } +export const EIP155_TEST_CHAINS = { + 'eip155:4': { + chainId: 4, + name: 'Ethereum Rinkeby', + logo: LOGO_BASE_URL + 'eip155:1.png', + rgb: '99, 125, 234' + }, + 'eip155:69': { + chainId: 69, + name: 'Optimism Kovan', + logo: LOGO_BASE_URL + 'eip155:10.png', + rgb: '233, 1, 1' + }, + 'eip155:80001': { + chainId: 80001, + name: 'Polygon Mumbai', + logo: LOGO_BASE_URL + 'eip155:137.png', + rgb: '130, 71, 229' + }, + 'eip155:421611': { + chainId: 421611, + name: 'Arbitrum Rinkeby', + logo: LOGO_BASE_URL + 'eip155:42161.png', + rgb: '44, 55, 75' + } +} + /** * Methods */ diff --git a/wallets/react-wallet-v2/src/pages/settings.tsx b/wallets/react-wallet-v2/src/pages/settings.tsx index 87de47c..22e64f5 100644 --- a/wallets/react-wallet-v2/src/pages/settings.tsx +++ b/wallets/react-wallet-v2/src/pages/settings.tsx @@ -1,12 +1,15 @@ import PageHeader from '@/components/PageHeader' +import SettingsStore from '@/store/SettingsStore' import { wallet } from '@/utils/WalletUtil' import { Card, Divider, Row, Switch, Text, useTheme } from '@nextui-org/react' import { useTheme as useNextTheme } from 'next-themes' import { Fragment } from 'react' +import { useSnapshot } from 'valtio' export default function SettingsPage() { const { setTheme } = useNextTheme() const { isDark, type } = useTheme() + const { testNets } = useSnapshot(SettingsStore.state) return ( @@ -29,7 +32,8 @@ export default function SettingsPage() { Testnets - Dissabled + + {testNets ? 'Enabled' : 'Disabled'} @@ -38,7 +42,7 @@ export default function SettingsPage() { Theme - setTheme(e.target.checked ? 'dark' : 'light')} />{' '} + setTheme(e.target.checked ? 'dark' : 'light')} /> {type} diff --git a/wallets/react-wallet-v2/src/store/SettingsStore.ts b/wallets/react-wallet-v2/src/store/SettingsStore.ts new file mode 100644 index 0000000..2771f4e --- /dev/null +++ b/wallets/react-wallet-v2/src/store/SettingsStore.ts @@ -0,0 +1,28 @@ +import { proxy } from 'valtio' + +/** + * Types + */ +interface State { + testNets: boolean +} + +/** + * State + */ +const state = proxy({ + testNets: false +}) + +/** + * Store / Actions + */ +const SettingsStore = { + state, + + toggleTestNets() { + state.testNets = !state.testNets + } +} + +export default SettingsStore From e43eab7b724d73b55303634933c1ad775c5f2942 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 15 Feb 2022 12:55:19 +0200 Subject: [PATCH 27/30] another attempt at ios fix --- wallets/react-wallet-v2/public/main.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wallets/react-wallet-v2/public/main.css b/wallets/react-wallet-v2/public/main.css index 3615e4a..02cf3ee 100644 --- a/wallets/react-wallet-v2/public/main.css +++ b/wallets/react-wallet-v2/public/main.css @@ -2,6 +2,14 @@ box-sizing: border-box; } +body, +html { + position: fixed; + height: calc(100vh - calc(100vh - 100%)); + width: 100vw; + overflow: hidden; +} + .routeTransition { width: 100%; height: 100%; From a9280ef124e6c7a3d362197f2687e7fd2d0a0cc3 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 15 Feb 2022 13:22:26 +0200 Subject: [PATCH 28/30] Minor layout fixes --- wallets/react-wallet-v2/public/main.css | 13 +++++------- .../react-wallet-v2/src/components/Layout.tsx | 8 ++++--- wallets/react-wallet-v2/src/pages/index.tsx | 21 ++++++++++++++++++- .../react-wallet-v2/src/pages/settings.tsx | 2 +- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/wallets/react-wallet-v2/public/main.css b/wallets/react-wallet-v2/public/main.css index 02cf3ee..fca7f32 100644 --- a/wallets/react-wallet-v2/public/main.css +++ b/wallets/react-wallet-v2/public/main.css @@ -1,21 +1,18 @@ * { box-sizing: border-box; + -ms-overflow-style: none; + scrollbar-width: none; } -body, -html { - position: fixed; - height: calc(100vh - calc(100vh - 100%)); - width: 100vw; - overflow: hidden; +::-webkit-scrollbar { + display: none; } .routeTransition { - width: 100%; - height: 100%; display: flex; flex: 1; flex-direction: column; + overflow: hidden; } .container { diff --git a/wallets/react-wallet-v2/src/components/Layout.tsx b/wallets/react-wallet-v2/src/components/Layout.tsx index a8aa1b1..4b65214 100644 --- a/wallets/react-wallet-v2/src/components/Layout.tsx +++ b/wallets/react-wallet-v2/src/components/Layout.tsx @@ -36,7 +36,7 @@ export default function Layout({ children, initialized }: Props) { justifyContent: initialized ? 'normal' : 'center', alignItems: initialized ? 'normal' : 'center', borderRadius: 0, - outline: 'none', + paddingBottom: 5, '@xs': { borderRadius: '$lg', @@ -63,9 +63,11 @@ export default function Layout({ children, initialized }: Props) { Accounts + + Mainnets + {Object.values(EIP155_CHAINS).map(({ name, logo, rgb }) => ( ))} + + {testNets ? ( + + + Testnets + + {Object.values(EIP155_TEST_CHAINS).map(({ name, logo, rgb }) => ( + + ))} + + ) : null} ) } diff --git a/wallets/react-wallet-v2/src/pages/settings.tsx b/wallets/react-wallet-v2/src/pages/settings.tsx index 22e64f5..0a4ebfd 100644 --- a/wallets/react-wallet-v2/src/pages/settings.tsx +++ b/wallets/react-wallet-v2/src/pages/settings.tsx @@ -17,7 +17,7 @@ export default function SettingsPage() { Mnemonic - + {wallet.mnemonic.phrase} From 6d5c679ca799ea7bdcfd41ee883d6a4c2b535593 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 15 Feb 2022 14:41:46 +0200 Subject: [PATCH 29/30] Parse and sign typed data --- .../react-wallet-v2/src/components/Modal.tsx | 2 + .../react-wallet-v2/src/data/EIP155Data.ts | 5 +- .../hooks/useWalletConnectEventsManager.ts | 12 ++ wallets/react-wallet-v2/src/pages/index.tsx | 4 +- .../react-wallet-v2/src/store/ModalStore.ts | 2 +- .../src/store/SettingsStore.ts | 7 +- .../react-wallet-v2/src/utils/HelperUtil.ts | 26 ++++ .../src/utils/RequestHandlerUtil.ts | 27 +++- .../react-wallet-v2/src/utils/WalletUtil.ts | 6 +- .../src/views/SessionSignModal.tsx | 9 +- .../src/views/SessionSignTypedDataModal.tsx | 121 ++++++++++++++++++ 11 files changed, 201 insertions(+), 20 deletions(-) create mode 100644 wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx diff --git a/wallets/react-wallet-v2/src/components/Modal.tsx b/wallets/react-wallet-v2/src/components/Modal.tsx index 29f6204..4f66a34 100644 --- a/wallets/react-wallet-v2/src/components/Modal.tsx +++ b/wallets/react-wallet-v2/src/components/Modal.tsx @@ -1,6 +1,7 @@ import ModalStore from '@/store/ModalStore' import SessionProposalModal from '@/views/SessionProposalModal' import SessionRequestModal from '@/views/SessionSignModal' +import SessionSignTypedDataModal from '@/views/SessionSignTypedDataModal' import { Modal as NextModal } from '@nextui-org/react' import { useSnapshot } from 'valtio' @@ -11,6 +12,7 @@ export default function Modal() { {view === 'SessionProposalModal' && } {view === 'SessionSignModal' && } + {view === 'SessionSignTypedDataModal' && } ) } diff --git a/wallets/react-wallet-v2/src/data/EIP155Data.ts b/wallets/react-wallet-v2/src/data/EIP155Data.ts index c9ecf2d..7e7a730 100644 --- a/wallets/react-wallet-v2/src/data/EIP155Data.ts +++ b/wallets/react-wallet-v2/src/data/EIP155Data.ts @@ -16,7 +16,7 @@ export type TEIP155Chain = keyof typeof EIP155_CHAINS /** * Chains */ -export const EIP155_CHAINS = { +export const EIP155_MAINNET_CHAINS = { 'eip155:1': { chainId: 1, name: 'Ethereum', @@ -70,6 +70,8 @@ export const EIP155_TEST_CHAINS = { } } +export const EIP155_CHAINS = { ...EIP155_MAINNET_CHAINS, ...EIP155_TEST_CHAINS } + /** * Methods */ @@ -78,6 +80,7 @@ export const EIP155_SIGNING_METHODS = { ETH_SIGN: 'eth_sign', ETH_SIGN_TRANSACTION: 'eth_signTransaction', ETH_SIGN_TYPED_DATA: 'eth_signTypedData', + ETH_SIGN_TYPED_DATA_V3: 'eth_signTypedData_v3', ETH_SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4', ETH_SIGN_RAW_TRANSACTION: 'eth_sendRawTransaction', ETH_SEND_TRANSACTION: 'eth_sendTransaction' diff --git a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts index d5497da..e1cd614 100644 --- a/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts +++ b/wallets/react-wallet-v2/src/hooks/useWalletConnectEventsManager.ts @@ -20,9 +20,21 @@ export default function useWalletConnectEventsManager(initialized: boolean) { const { method } = request const requestSession = await walletConnectClient.session.get(topic) + // Hanle message signing requests of various formats if ([EIP155_SIGNING_METHODS.ETH_SIGN, EIP155_SIGNING_METHODS.PERSONAL_SIGN].includes(method)) { ModalStore.open('SessionSignModal', { requestEvent, requestSession }) } + + // Hanle data signing requests of various formats + if ( + [ + EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA, + EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3, + EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4 + ].includes(method) + ) { + ModalStore.open('SessionSignTypedDataModal', { requestEvent, requestSession }) + } }, []) useEffect(() => { diff --git a/wallets/react-wallet-v2/src/pages/index.tsx b/wallets/react-wallet-v2/src/pages/index.tsx index 36d6a0e..5946476 100644 --- a/wallets/react-wallet-v2/src/pages/index.tsx +++ b/wallets/react-wallet-v2/src/pages/index.tsx @@ -1,6 +1,6 @@ import AccountCard from '@/components/AccountCard' import PageHeader from '@/components/PageHeader' -import { EIP155_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data' +import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data' import SettingsStore from '@/store/SettingsStore' import { wallet } from '@/utils/WalletUtil' import { Text } from '@nextui-org/react' @@ -16,7 +16,7 @@ export default function HomePage() { Mainnets - {Object.values(EIP155_CHAINS).map(({ name, logo, rgb }) => ( + {Object.values(EIP155_MAINNET_CHAINS).map(({ name, logo, rgb }) => ( ))} diff --git a/wallets/react-wallet-v2/src/store/ModalStore.ts b/wallets/react-wallet-v2/src/store/ModalStore.ts index b46b454..2fe913d 100644 --- a/wallets/react-wallet-v2/src/store/ModalStore.ts +++ b/wallets/react-wallet-v2/src/store/ModalStore.ts @@ -13,7 +13,7 @@ interface ModalData { interface State { open: boolean - view?: 'SessionProposalModal' | 'SessionSignModal' + view?: 'SessionProposalModal' | 'SessionSignModal' | 'SessionSignTypedDataModal' data?: ModalData } diff --git a/wallets/react-wallet-v2/src/store/SettingsStore.ts b/wallets/react-wallet-v2/src/store/SettingsStore.ts index 2771f4e..05c664f 100644 --- a/wallets/react-wallet-v2/src/store/SettingsStore.ts +++ b/wallets/react-wallet-v2/src/store/SettingsStore.ts @@ -11,7 +11,7 @@ interface State { * State */ const state = proxy({ - testNets: false + testNets: Boolean(localStorage.getItem('TEST_NETS')) ?? false }) /** @@ -22,6 +22,11 @@ const SettingsStore = { toggleTestNets() { state.testNets = !state.testNets + if (state.testNets) { + localStorage.setItem('TEST_NETS', 'YES') + } else { + localStorage.removeItem('TEST_NETS') + } } } diff --git a/wallets/react-wallet-v2/src/utils/HelperUtil.ts b/wallets/react-wallet-v2/src/utils/HelperUtil.ts index 62c3567..0703c53 100644 --- a/wallets/react-wallet-v2/src/utils/HelperUtil.ts +++ b/wallets/react-wallet-v2/src/utils/HelperUtil.ts @@ -26,3 +26,29 @@ export function convertHexToUtf8(value: string) { return value } + +/** + * Gets message from various signing request methods by filtering out + * a value that is not an address (thus is a message). + * If it is a hex string, it gets converted to utf8 string + */ +export function getSignParamsMessage(params: string[]) { + const message = params.filter(p => !utils.isAddress(p))[0] + + return convertHexToUtf8(message) +} + +/** + * Gets data from various signTypedData request methods by filtering out + * a value that is not an address (thus is data). + * If data is a string convert it to object + */ +export function getSignTypedDataParamsData(params: string[]) { + const data = params.filter(p => !utils.isAddress(p))[0] + + if (typeof data === 'string') { + return JSON.parse(data) + } + + return data +} diff --git a/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts index 498e8b5..1db5ef5 100644 --- a/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts +++ b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts @@ -1,5 +1,5 @@ import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data' -import { convertHexToUtf8 } from '@/utils/HelperUtil' +import { getSignParamsMessage, getSignTypedDataParamsData } from '@/utils/HelperUtil' import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils' import { RequestEvent } from '@walletconnect/types' import { ERROR } from '@walletconnect/utils' @@ -9,13 +9,28 @@ export async function approveEIP155Request(request: RequestEvent['request'], wal const { method, params, id } = request switch (method) { + /** + * Handle message signing requests + */ case EIP155_SIGNING_METHODS.PERSONAL_SIGN: - const personalSignResult = await wallet.signMessage(convertHexToUtf8(params[0])) - return formatJsonRpcResult(id, personalSignResult) - case EIP155_SIGNING_METHODS.ETH_SIGN: - const ethSignResult = await wallet.signMessage(convertHexToUtf8(params[1])) - return formatJsonRpcResult(id, ethSignResult) + const message = getSignParamsMessage(params) + const signedMessage = await wallet.signMessage(message) + return formatJsonRpcResult(id, signedMessage) + + /** + * Handle data signing requests + */ + case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA: + case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3: + case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4: + const { domain, types, message: data } = getSignTypedDataParamsData(params) + + // https://github.com/ethers-io/ethers.js/issues/687#issuecomment-714069471 + delete types.EIP712Domain + + const signedData = await wallet._signTypedData(domain, types, data) + return formatJsonRpcResult(id, signedData) default: throw new Error(ERROR.UNKNOWN_JSONRPC_METHOD.format().message) diff --git a/wallets/react-wallet-v2/src/utils/WalletUtil.ts b/wallets/react-wallet-v2/src/utils/WalletUtil.ts index 527a66c..be73ad6 100644 --- a/wallets/react-wallet-v2/src/utils/WalletUtil.ts +++ b/wallets/react-wallet-v2/src/utils/WalletUtil.ts @@ -1,17 +1,15 @@ import { Wallet } from 'ethers' -const STORAGE_KEY = 'WALLET_MNEMONIC' - export let wallet: Wallet export function createOrRestoreWallet() { - const mnemonic = localStorage.getItem(STORAGE_KEY) + const mnemonic = localStorage.getItem('WALLET_MNEMONIC') if (mnemonic) { wallet = Wallet.fromMnemonic(mnemonic) } else { wallet = Wallet.createRandom() // Don't store mnemonic in local storage in a production project! - localStorage.setItem(STORAGE_KEY, wallet.mnemonic.phrase) + localStorage.setItem('WALLET_MNEMONIC', wallet.mnemonic.phrase) } } diff --git a/wallets/react-wallet-v2/src/views/SessionSignModal.tsx b/wallets/react-wallet-v2/src/views/SessionSignModal.tsx index 57a66c5..5c8a6d2 100644 --- a/wallets/react-wallet-v2/src/views/SessionSignModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionSignModal.tsx @@ -1,6 +1,6 @@ -import { EIP155_CHAINS, EIP155_SIGNING_METHODS, TEIP155Chain } from '@/data/EIP155Data' +import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data' import ModalStore from '@/store/ModalStore' -import { convertHexToUtf8 } from '@/utils/HelperUtil' +import { getSignParamsMessage } from '@/utils/HelperUtil' import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil' import { walletConnectClient } from '@/utils/WalletConnectUtil' import { wallet } from '@/utils/WalletUtil' @@ -24,8 +24,7 @@ export default function SessionSignModal() { const { name, icons, url } = requestSession.peer.metadata // Get message, convert it to UTF8 string if it is valid hex - let message = method === EIP155_SIGNING_METHODS.PERSONAL_SIGN ? params[0] : params[1] - message = convertHexToUtf8(message) + const message = getSignParamsMessage(params) // Handle approve action (logic varies based on request method) async function onApprove() { @@ -54,7 +53,7 @@ export default function SessionSignModal() { return ( - Request + Sign Message diff --git a/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx b/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx new file mode 100644 index 0000000..025ce1e --- /dev/null +++ b/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx @@ -0,0 +1,121 @@ +import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data' +import ModalStore from '@/store/ModalStore' +import { getSignTypedDataParamsData } from '@/utils/HelperUtil' +import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil' +import { walletConnectClient } from '@/utils/WalletConnectUtil' +import { wallet } from '@/utils/WalletUtil' +import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' +import { Fragment } from 'react' + +export default function SessionSignTypedDataModal() { + // Get request and wallet data from store + const requestEvent = ModalStore.state.data?.requestEvent + const requestSession = ModalStore.state.data?.requestSession + + // Ensure request and wallet are defined + if (!requestEvent || !requestSession) { + return Missing request data + } + + // Get required request data + const { chainId } = requestEvent + const { method, params } = requestEvent.request + const { protocol } = requestSession.relay + const { name, icons, url } = requestSession.peer.metadata + + // Get data + const data = getSignTypedDataParamsData(params) + + // Handle approve action (logic varies based on request method) + async function onApprove() { + if (requestEvent) { + const response = await approveEIP155Request(requestEvent.request, wallet) + await walletConnectClient.respond({ + topic: requestEvent.topic, + response + }) + ModalStore.close() + } + } + + // Handle reject action + async function onReject() { + if (requestEvent) { + const response = rejectEIP155Request(requestEvent.request) + await walletConnectClient.respond({ + topic: requestEvent.topic, + response + }) + ModalStore.close() + } + } + + return ( + + + Sign Typed Data + + + + + + + + + + {name} + {url} + + + + + + + + Blockchain + + {EIP155_CHAINS[chainId as TEIP155Chain]?.name ?? chainId} + + + + + + + + + Message + {JSON.stringify(data)} + + + + + + + + Method + {method} + + + + + + + + Relay Protocol + {protocol} + + + + + + + + + + + ) +} From 914f91967a11110ede0ce4ac2b57bb7aec8f0714 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 15 Feb 2022 15:28:30 +0200 Subject: [PATCH 30/30] SessionTypedData modal --- wallets/react-wallet-v2/package.json | 3 +- wallets/react-wallet-v2/public/main.css | 9 + .../src/utils/RequestHandlerUtil.ts | 3 + .../src/views/SessionSignTypedDataModal.tsx | 38 +- wallets/react-wallet-v2/yarn.lock | 422 +++++++++++++++++- 5 files changed, 464 insertions(+), 11 deletions(-) diff --git a/wallets/react-wallet-v2/package.json b/wallets/react-wallet-v2/package.json index 48dbcdb..796627c 100644 --- a/wallets/react-wallet-v2/package.json +++ b/wallets/react-wallet-v2/package.json @@ -20,7 +20,8 @@ "framer-motion": "6.2.6", "ethers": "5.5.4", "valtio": "1.3.0", - "@json-rpc-tools/utils": "1.7.6" + "@json-rpc-tools/utils": "1.7.6", + "react-code-blocks": "0.0.9-0" }, "devDependencies": { "@walletconnect/types": "2.0.0-beta.22", diff --git a/wallets/react-wallet-v2/public/main.css b/wallets/react-wallet-v2/public/main.css index fca7f32..d862414 100644 --- a/wallets/react-wallet-v2/public/main.css +++ b/wallets/react-wallet-v2/public/main.css @@ -40,4 +40,13 @@ .qrIcon { opacity: 0.3; +} + +.codeBlock code { + flex: 1; +} + +.codeBlock span { + background-color: transparent !important; + overflow: scroll; } \ No newline at end of file diff --git a/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts index 1db5ef5..563b8a2 100644 --- a/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts +++ b/wallets/react-wallet-v2/src/utils/RequestHandlerUtil.ts @@ -32,6 +32,9 @@ export async function approveEIP155Request(request: RequestEvent['request'], wal const signedData = await wallet._signTypedData(domain, types, data) return formatJsonRpcResult(id, signedData) + /** + * Handle unsuported methods + */ default: throw new Error(ERROR.UNKNOWN_JSONRPC_METHOD.format().message) } diff --git a/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx b/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx index 025ce1e..ad70ab1 100644 --- a/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx +++ b/wallets/react-wallet-v2/src/views/SessionSignTypedDataModal.tsx @@ -6,6 +6,7 @@ import { walletConnectClient } from '@/utils/WalletConnectUtil' import { wallet } from '@/utils/WalletUtil' import { Avatar, Button, Col, Container, Divider, Link, Modal, Row, Text } from '@nextui-org/react' import { Fragment } from 'react' +import { CodeBlock, codepen } from 'react-code-blocks' export default function SessionSignTypedDataModal() { // Get request and wallet data from store @@ -82,9 +83,42 @@ export default function SessionSignTypedDataModal() { - + + Domain + + + + + + + + + Types + + + + + + + + Message - {JSON.stringify(data)} + diff --git a/wallets/react-wallet-v2/yarn.lock b/wallets/react-wallet-v2/yarn.lock index 439b972..db648e3 100644 --- a/wallets/react-wallet-v2/yarn.lock +++ b/wallets/react-wallet-v2/yarn.lock @@ -2,6 +2,92 @@ # yarn lockfile v1 +"@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/generator@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.0.tgz#7bd890ba706cd86d3e2f727322346ffdbf98f65e" + integrity sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw== + dependencies: + "@babel/types" "^7.17.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.16.7", "@babel/parser@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.0.tgz#f0ac33eddbe214e4105363bb17c3341c5ffcc43c" + integrity sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw== + "@babel/runtime-corejs3@^7.10.2": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.16.8.tgz#ea533d96eda6fdc76b1812248e9fbd0c11d4a1a7" @@ -24,14 +110,47 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.6.2": +"@babel/runtime@^7.10.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.6.2": version "7.17.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== dependencies: regenerator-runtime "^0.13.4" -"@emotion/is-prop-valid@^0.8.2": +"@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.4.5": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.0.tgz#3143e5066796408ccc880a33ecd3184f3e75cd30" + integrity sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.0" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.0" + "@babel/types" "^7.17.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.16.7", "@babel/types@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@emotion/is-prop-valid@^0.8.2", "@emotion/is-prop-valid@^0.8.8": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== @@ -43,6 +162,16 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== +"@emotion/stylis@^0.8.4": + version "0.8.5" + resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" + integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== + +"@emotion/unitless@^0.7.4": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + "@eslint/eslintrc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.1.0.tgz#583d12dbec5d4f22f333f9669f7d0b7c7815b4d3" @@ -1025,6 +1154,21 @@ axobject-query@^2.2.0: resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== +"babel-plugin-styled-components@>= 1.12.0": + version "2.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.2.tgz#0fac11402dc9db73698b55847ab1dc73f5197c54" + integrity sha512-7eG5NE8rChnNTDxa6LQfynwgHTVOYYaHJbUYSlOhk8QBXIQiMBKq4gyfHBBKPrxUcVBXVJL61ihduCpCQbuNbw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-module-imports" "^7.16.0" + babel-plugin-syntax-jsx "^6.18.0" + lodash "^4.17.11" + +babel-plugin-syntax-jsx@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -1115,12 +1259,17 @@ camelcase@5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== +camelize@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= + caniuse-lite@^1.0.30001283: version "1.0.30001305" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001305.tgz#02cd8031df07c4fcb117aa2ecc4899122681bd4c" integrity sha512-p7d9YQMji8haf0f+5rbcv9WlQ+N5jMPfRAnUmZRlNxsNeBO3Yr7RYG6M2uTY1h9tCVdlkJg6YNNc4kiAiBLdWA== -chalk@2.4.2: +chalk@2.4.2, chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1137,11 +1286,35 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +clipboard@^2.0.0: + version "2.0.10" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.10.tgz#e61f6f7139ac5044c58c0484dcac9fb2a918bfd6" + integrity sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g== + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + clsx@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" @@ -1176,6 +1349,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1205,6 +1383,20 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= + +css-to-react-native@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" + integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== + dependencies: + camelize "^1.0.0" + css-color-keywords "^1.0.0" + postcss-value-parser "^4.0.2" + csstype@^3.0.2: version "3.0.10" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" @@ -1234,7 +1426,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== @@ -1270,6 +1462,11 @@ define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +delegate@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" + integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -1673,6 +1870,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fault@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" + integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== + dependencies: + format "^0.2.0" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -1722,6 +1926,11 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== +format@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" + integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= + framer-motion@6.2.6: version "6.2.6" resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.2.6.tgz#75277b4944a1234beaf7453da19028bbf4f75cce" @@ -1836,6 +2045,11 @@ glob@^7.1.3, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globals@^13.6.0, globals@^13.9.0: version "13.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" @@ -1855,6 +2069,13 @@ globby@^11.0.4: merge2 "^1.4.1" slash "^3.0.0" +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= + dependencies: + delegate "^3.1.2" + has-bigints@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" @@ -1902,11 +2123,31 @@ 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" +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + +hastscript@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.2.tgz#bde2c2e56d04c62dd24e8c5df288d050a355fb8a" + integrity sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ== + dependencies: + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + hey-listen@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68" integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== +highlight.js@~9.15.0, highlight.js@~9.15.1: + version "9.15.10" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2" + integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw== + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -1916,6 +2157,13 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.0.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -1971,6 +2219,19 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -2005,6 +2266,11 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -2029,6 +2295,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + is-negative-zero@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -2110,7 +2381,7 @@ js-sha3@0.8.0: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -"js-tokens@^3.0.0 || ^4.0.0": +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -2122,6 +2393,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -2215,6 +2491,11 @@ lodash.union@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= +lodash@^4.17.11: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -2222,6 +2503,14 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lowlight@1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.12.1.tgz#014acf8dd73a370e02ff1cc61debcde3bb1681eb" + integrity sha512-OqaVxMGIESnawn+TU/QMV5BJLbUghUfjDWPAtFqDYDmDtr4FnB+op8xM+pR7nKlauHNUHXGt0VgWatFB8voS5w== + dependencies: + fault "^1.0.2" + highlight.js "~9.15.0" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -2464,6 +2753,18 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-entities@^1.1.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" + integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -2545,6 +2846,11 @@ popmotion@11.0.3: style-value-types "5.0.0" tslib "^2.1.0" +postcss-value-parser@^4.0.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + postcss@8.4.5: version "8.4.5" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" @@ -2583,6 +2889,18 @@ prettier@2.5.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== +prismjs@^1.8.4: + version "1.26.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.26.0.tgz#16881b594828bb6b45296083a8cbab46b0accd47" + integrity sha512-HUoH9C5Z3jKkl3UunCyiD5jwk0+Hz0fIgQ2nbwU2Oo/ceuTAQAg+pPVnfdt2TJWRVLcxKh9iuoYDUSc8clb5UQ== + +prismjs@~1.17.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.17.1.tgz#e669fcbd4cdd873c35102881c33b14d0d68519be" + integrity sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q== + optionalDependencies: + clipboard "^2.0.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -2602,6 +2920,13 @@ prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.13.1" +property-information@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + proxy-compare@2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/proxy-compare/-/proxy-compare-2.0.2.tgz#343e624d0ec399dfbe575f1d365d4fa042c9fc69" @@ -2657,6 +2982,16 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-code-blocks@0.0.9-0: + version "0.0.9-0" + resolved "https://registry.yarnpkg.com/react-code-blocks/-/react-code-blocks-0.0.9-0.tgz#0c6d04d8a40b74cffe95f24f1a8e62a0fda8c014" + integrity sha512-jdYJVZwGtsr6WIUaqILy5fkF1acf57YV5s0V3+w5o9v3omYnqBeO6EuZi1Vf2x1hahkYGEedsp46+ofdkYlqyw== + dependencies: + "@babel/runtime" "^7.10.4" + react-syntax-highlighter "^12.2.1" + styled-components "^5.1.1" + tslib "^2.0.0" + react-dom@17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -2666,7 +3001,7 @@ react-dom@17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" -react-is@^16.13.1: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -2679,6 +3014,17 @@ react-qr-reader-es6@2.2.1-2: jsqr-es6 "^1.4.0-1" prop-types "^15.7.2" +react-syntax-highlighter@^12.2.1: + version "12.2.1" + resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-12.2.1.tgz#14d78352da1c1c3f93c6698b70ec7c706b83493e" + integrity sha512-CTsp0ZWijwKRYFg9xhkWD4DSpQqE4vb2NKVMdPAkomnILSmsNBHE0n5GuI5zB+PU3ySVvXvdt9jo+ViD9XibCA== + dependencies: + "@babel/runtime" "^7.3.1" + highlight.js "~9.15.1" + lowlight "1.12.1" + prismjs "^1.8.4" + refractor "^2.4.1" + react@17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -2709,6 +3055,15 @@ readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable string_decoder "^1.1.1" util-deprecate "^1.0.1" +refractor@^2.4.1: + version "2.10.1" + resolved "https://registry.yarnpkg.com/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e" + integrity sha512-Xh9o7hQiQlDbxo5/XkOX6H+x/q8rmlmZKr97Ie1Q8ZM32IRRd3B/UxuA/yXDW79DBSXGWxm2yRTbcTVmAciJRw== + dependencies: + hastscript "^5.0.0" + parse-entities "^1.1.2" + prismjs "~1.17.0" + regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" @@ -2801,6 +3156,11 @@ scrypt-js@3.0.1: resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== +select@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= + semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" @@ -2818,6 +3178,11 @@ set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -2876,6 +3241,16 @@ source-map-js@^1.0.1: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + split-on-first@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" @@ -2992,12 +3367,28 @@ style-value-types@5.0.0: hey-listen "^1.0.8" tslib "^2.1.0" +styled-components@^5.1.1: + version "5.3.3" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.3.tgz#312a3d9a549f4708f0fb0edc829eb34bde032743" + integrity sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/traverse" "^7.4.5" + "@emotion/is-prop-valid" "^0.8.8" + "@emotion/stylis" "^0.8.4" + "@emotion/unitless" "^0.7.4" + babel-plugin-styled-components ">= 1.12.0" + css-to-react-native "^3.0.0" + hoist-non-react-statics "^3.0.0" + shallowequal "^1.1.0" + supports-color "^5.5.0" + styled-jsx@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== -supports-color@^5.3.0: +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -3042,6 +3433,16 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +tiny-emitter@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" + integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -3064,7 +3465,7 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: +tslib@^2.0.0, tslib@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -3198,6 +3599,11 @@ ws@^8.3.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b" integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA== +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"