diff --git a/App.tsx b/App.tsx
index f46a152dc7..43f7d00a7c 100644
--- a/App.tsx
+++ b/App.tsx
@@ -2,10 +2,10 @@ import * as SplashScreen from 'expo-splash-screen'
import React from 'react'
import { Provider as StoreProvider } from 'react-redux'
import './_shim'
-import { Logging } from './app/api/logging'
+import { Logging } from './app/api'
import { NetworkProvider } from './app/contexts/NetworkContext'
import { PlaygroundProvider, useConnectedPlayground } from './app/contexts/PlaygroundContext'
-import { WalletManagementProvider } from './app/contexts/WalletManagementContext'
+import { WalletPersistenceProvider } from './app/contexts/WalletPersistenceContext'
import { WhaleProvider } from './app/contexts/WhaleContext'
import { useCachedResources } from './app/hooks/useCachedResources'
import ErrorBoundary from './app/screens/ErrorBoundary/ErrorBoundary'
@@ -41,11 +41,11 @@ export default function App (): JSX.Element | null {
-
+
-
+
diff --git a/app/api/index.ts b/app/api/index.ts
index 5167b42c98..7a3f66392f 100644
--- a/app/api/index.ts
+++ b/app/api/index.ts
@@ -1,3 +1,2 @@
-export * from './wallet/persistence'
export * from './storage'
export * from './logging'
diff --git a/app/api/wallet/provider/index.test.ts b/app/api/wallet/index.test.ts
similarity index 73%
rename from app/api/wallet/provider/index.test.ts
rename to app/api/wallet/index.test.ts
index 9f95120f61..d7b4929823 100644
--- a/app/api/wallet/provider/index.test.ts
+++ b/app/api/wallet/index.test.ts
@@ -1,8 +1,9 @@
import { MnemonicProviderData } from "@defichain/jellyfish-wallet-mnemonic";
import { WhaleApiClient } from "@defichain/whale-api-client";
-import { EnvironmentNetwork } from "../../../environment";
-import { WalletPersistenceData, WalletType } from "../persistence";
+import { EnvironmentNetwork } from "../../environment";
+import { WalletPersistenceData, WalletType } from "./persistence";
import { initWhaleWallet } from "./index";
+import { MnemonicUnprotected } from "./provider/mnemonic_unprotected";
beforeEach(async () => {
jest.clearAllMocks()
@@ -22,23 +23,11 @@ it('should initWhaleWallet', async () => {
}
}
- const wallet = initWhaleWallet(data, network, client)
+ const provider = MnemonicUnprotected.initProvider(data, network)
+ const wallet = initWhaleWallet(provider, network, client)
expect(wallet.get(0).withTransactionBuilder().utxo).toBeDefined()
expect(wallet.get(0).withTransactionBuilder().dex).toBeDefined()
expect(wallet.get(0).withTransactionBuilder().account).toBeDefined()
expect(wallet.get(0).withTransactionBuilder().liqPool).toBeDefined()
-});
-
-
-it('should fail as wallet type not available', async () => {
- const data: WalletPersistenceData = {
- version: "v1",
- type: undefined as any,
- raw: ""
- }
-
- expect(() => {
- initWhaleWallet(data, network, client)
- }).toThrow('wallet undefined not available')
})
diff --git a/app/api/wallet/index.ts b/app/api/wallet/index.ts
new file mode 100644
index 0000000000..82ec86d0ce
--- /dev/null
+++ b/app/api/wallet/index.ts
@@ -0,0 +1,21 @@
+import { JellyfishWallet, WalletHdNode, WalletHdNodeProvider } from '@defichain/jellyfish-wallet'
+import { WhaleApiClient } from '@defichain/whale-api-client'
+import { WhaleWalletAccount, WhaleWalletAccountProvider } from '@defichain/whale-api-wallet'
+import { EnvironmentNetwork } from '../../environment'
+import { getJellyfishNetwork } from './network'
+
+/**
+ * Whale JellyfishWallet connected to Whale APIs via the Ocean Infrastructure
+ */
+export type WhaleWallet = JellyfishWallet
+
+export function initWhaleWallet (provider: WalletHdNodeProvider, network: EnvironmentNetwork, client: WhaleApiClient): WhaleWallet {
+ const accountProvider = new WhaleWalletAccountProvider(client, getJellyfishNetwork(network))
+ return new JellyfishWallet(provider, accountProvider)
+}
+
+export * from './provider/mnemonic_encrypted'
+export * from './provider/mnemonic_unprotected'
+export * from './network'
+export * from './passcode_attempt'
+export * from './persistence'
diff --git a/app/api/wallet/passcode_attempt.ts b/app/api/wallet/passcode_attempt.ts
new file mode 100644
index 0000000000..848bd2ff6d
--- /dev/null
+++ b/app/api/wallet/passcode_attempt.ts
@@ -0,0 +1,20 @@
+import { StorageAPI } from '../storage'
+
+const KEY = 'PASSCODE_ATTEMPT.count'
+
+async function get (): Promise {
+ const str = await StorageAPI.getItem(KEY)
+ return str === undefined ? 0 : Number(str)
+}
+
+async function set (count: number): Promise {
+ await StorageAPI.setItem(KEY, `${count}`)
+}
+
+/**
+ * Failed passcode input counter persistence layer
+ */
+export const PasscodeAttemptCounter = {
+ set,
+ get
+}
diff --git a/app/api/wallet/persistence.ts b/app/api/wallet/persistence.ts
index e8e1eb2c61..cbb6828d3f 100644
--- a/app/api/wallet/persistence.ts
+++ b/app/api/wallet/persistence.ts
@@ -1,7 +1,8 @@
import { StorageAPI } from '../storage'
export enum WalletType {
- MNEMONIC_UNPROTECTED = 'MNEMONIC_UNPROTECTED'
+ MNEMONIC_UNPROTECTED = 'MNEMONIC_UNPROTECTED',
+ MNEMONIC_ENCRYPTED = 'MNEMONIC_ENCRYPTED'
}
export interface WalletPersistenceData {
diff --git a/app/api/wallet/provider/index.ts b/app/api/wallet/provider/index.ts
deleted file mode 100644
index 30270e9a51..0000000000
--- a/app/api/wallet/provider/index.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { JellyfishWallet, WalletHdNode, WalletHdNodeProvider } from '@defichain/jellyfish-wallet'
-import { WhaleApiClient } from '@defichain/whale-api-client'
-import { WhaleWalletAccount, WhaleWalletAccountProvider } from '@defichain/whale-api-wallet'
-import { EnvironmentNetwork } from '../../../environment'
-import { getJellyfishNetwork } from '../network'
-import { WalletPersistenceData, WalletType } from '../persistence'
-import { MnemonicUnprotected } from './mnemonic_unprotected'
-
-/**
- * Whale JellyfishWallet connected to Whale APIs via the Ocean Infrastructure
- */
-export type WhaleWallet = JellyfishWallet
-
-export function initWhaleWallet (data: WalletPersistenceData, network: EnvironmentNetwork, client: WhaleApiClient): WhaleWallet {
- const jellyfishNetwork = getJellyfishNetwork(network)
-
- const walletProvider = resolveProvider(data, network)
- const accountProvider = new WhaleWalletAccountProvider(client, jellyfishNetwork)
-
- return new JellyfishWallet(walletProvider, accountProvider)
-}
-
-/**
- * @param {WalletPersistenceData} data to resolve wallet provider for init
- * @param {EnvironmentNetwork} network
- */
-function resolveProvider (data: WalletPersistenceData, network: EnvironmentNetwork): WalletHdNodeProvider {
- switch (data.type) {
- case WalletType.MNEMONIC_UNPROTECTED:
- return MnemonicUnprotected.initProvider(data, network)
-
- default:
- throw new Error(`wallet ${data.type as string} not available`)
- }
-}
diff --git a/app/api/wallet/provider/mnemonic_encrypted.ts b/app/api/wallet/provider/mnemonic_encrypted.ts
new file mode 100644
index 0000000000..dae255c9eb
--- /dev/null
+++ b/app/api/wallet/provider/mnemonic_encrypted.ts
@@ -0,0 +1,51 @@
+import {
+ EncryptedHdNodeProvider,
+ EncryptedProviderData,
+ PrivateKeyEncryption,
+ PromptPassphrase,
+ Scrypt
+} from '@defichain/jellyfish-wallet-encrypted'
+import * as Random from 'expo-random'
+import { EnvironmentNetwork } from '../../../environment'
+import { getBip32Option } from '../network'
+import { WalletPersistenceData, WalletType } from '../persistence'
+
+const encryption = new PrivateKeyEncryption(new Scrypt(), numOfBytes => {
+ const bytes = Random.getRandomBytes(numOfBytes)
+ return Buffer.from(bytes)
+})
+
+function initProvider (
+ data: WalletPersistenceData,
+ network: EnvironmentNetwork,
+ promptPassphrase: PromptPassphrase
+): EncryptedHdNodeProvider {
+ if (data.type !== WalletType.MNEMONIC_ENCRYPTED || data.version !== 'v1') {
+ throw new Error('Unexpected WalletPersistenceData')
+ }
+
+ const bip32Options = getBip32Option(network)
+ return EncryptedHdNodeProvider.init(data.raw, bip32Options, encryption, promptPassphrase)
+}
+
+async function toData (mnemonic: string[], network: EnvironmentNetwork, passphrase: string): Promise> {
+ const options = getBip32Option(network)
+ const data = await EncryptedHdNodeProvider.wordsToEncryptedData(mnemonic, options, encryption, passphrase)
+
+ return {
+ version: 'v1',
+ type: WalletType.MNEMONIC_ENCRYPTED,
+ raw: data
+ }
+}
+
+export const MnemonicEncrypted = {
+ initProvider,
+ toData,
+ /**
+ * Convenience Abandon23 Art on Playground Network Data
+ */
+ Abandon23Playground: toData([
+ 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'abandon', 'art'
+ ], EnvironmentNetwork.LocalPlayground, '123456')
+}
diff --git a/app/contexts/WalletContext.tsx b/app/contexts/WalletContext.tsx
index 9ab1207e4d..9008e42d15 100644
--- a/app/contexts/WalletContext.tsx
+++ b/app/contexts/WalletContext.tsx
@@ -1,9 +1,17 @@
-import React, { createContext, useContext, useEffect, useState } from 'react'
-import { useDispatch } from 'react-redux'
-import { Logging } from '../api/logging'
-import { WhaleWallet } from '../api/wallet/provider'
-import { wallet as store } from '../store/wallet'
-import { useWalletManagementContext } from './WalletManagementContext'
+import { EncryptedProviderData } from '@defichain/jellyfish-wallet-encrypted'
+import { MnemonicProviderData } from '@defichain/jellyfish-wallet-mnemonic'
+import { useNavigation } from '@react-navigation/native'
+import React, { createContext, PropsWithChildren, useCallback, useContext, useMemo } from 'react'
+import {
+ initWhaleWallet,
+ MnemonicEncrypted,
+ MnemonicUnprotected,
+ WalletPersistenceData,
+ WalletType,
+ WhaleWallet
+} from '../api/wallet'
+import { useNetworkContext } from './NetworkContext'
+import { useWhaleApiClient } from './WhaleContext'
const WalletContext = createContext(undefined as any)
@@ -11,24 +19,73 @@ export function useWallet (): WhaleWallet {
return useContext(WalletContext)
}
-export function WalletProvider (props: React.PropsWithChildren): JSX.Element | null {
- const dispatch = useDispatch()
- const management = useWalletManagementContext()
- const wallet = management.wallets[0]
-
- const [isLoaded, setLoaded] = useState(false)
+interface WalletProviderProps extends PropsWithChildren {
+ data: WalletPersistenceData
+}
- useEffect(() => {
- wallet.get(0).getAddress().then(address => {
- dispatch(store.actions.setAddress(address))
- setLoaded(true)
- }).catch(Logging.error)
- }, [management.wallets])
+/**
+ * Automatically determine the correct WalletProvider to use based on the wallet type.
+ */
+export function WalletProvider (props: WalletProviderProps): JSX.Element | null {
+ if (props.data.type === WalletType.MNEMONIC_UNPROTECTED) {
+ return (
+
+ {props.children}
+
+ )
+ }
- if (!isLoaded) {
- return null
+ if (props.data.type === WalletType.MNEMONIC_ENCRYPTED) {
+ return (
+
+ {props.children}
+
+ )
}
+ throw new Error(`wallet type: ${props.data.type as string} not available`)
+}
+
+function MnemonicUnprotectedProvider (props: WalletProviderProps): JSX.Element | null {
+ const { network } = useNetworkContext()
+ const client = useWhaleApiClient()
+
+ const wallet = useMemo(() => {
+ const provider = MnemonicUnprotected.initProvider(props.data, network)
+ return initWhaleWallet(provider, network, client)
+ }, [])
+
+ return (
+
+ {props.children}
+
+ )
+}
+
+function MnemonicEncryptedProvider (props: WalletProviderProps): JSX.Element | null {
+ const { network } = useNetworkContext()
+ const client = useWhaleApiClient()
+ const navigation = useNavigation()
+
+ const promptPassphrase = useCallback(async () => {
+ return await new Promise((resolve, reject) => {
+ // TODO(ivan): implementation
+ navigation.navigate('PromptPassphrase', {
+ resolve (passphrase: string) {
+ resolve(passphrase)
+ },
+ reject (error: Error) {
+ reject(error)
+ }
+ })
+ })
+ }, [])
+
+ const wallet = useMemo(() => {
+ const provider = MnemonicEncrypted.initProvider(props.data, network, promptPassphrase)
+ return initWhaleWallet(provider, network, client)
+ }, [])
+
return (
{props.children}
diff --git a/app/contexts/WalletManagementContext.tsx b/app/contexts/WalletManagementContext.tsx
deleted file mode 100644
index ea1a452c77..0000000000
--- a/app/contexts/WalletManagementContext.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'
-import { Logging } from '../api/logging'
-import { WalletPersistence, WalletPersistenceData } from '../api/wallet/persistence'
-import { initWhaleWallet, WhaleWallet } from '../api/wallet/provider'
-import { useNetworkContext } from './NetworkContext'
-import { useWhaleApiClient } from './WhaleContext'
-
-interface WalletManagement {
- wallets: WhaleWallet[]
- /**
- * @param {WalletPersistenceData} data to set, only 1 wallet is supported for now
- */
- setWallet: (data: WalletPersistenceData) => Promise
- clearWallets: () => Promise
-}
-
-const WalletManagementContext = createContext(undefined as any)
-
-/**
- * WalletManagement Context wrapped within
- *
- * This context enable wallet management by allow access to all configured wallets.
- * Setting, removing and getting individual wallet.
- */
-export function useWalletManagementContext (): WalletManagement {
- return useContext(WalletManagementContext)
-}
-
-export function WalletManagementProvider (props: React.PropsWithChildren): JSX.Element | null {
- const { network } = useNetworkContext()
- const client = useWhaleApiClient()
- const [dataList, setDataList] = useState>>([])
-
- useEffect(() => {
- WalletPersistence.get().then(dataList => {
- setDataList(dataList)
- }).catch(Logging.error)
- }, [network])
-
- const wallets = useMemo(() => {
- return dataList.map(data => initWhaleWallet(data, network, client))
- }, [dataList])
-
- const management: WalletManagement = {
- wallets: wallets,
- async setWallet (data: WalletPersistenceData): Promise {
- await WalletPersistence.set([data])
- setDataList(await WalletPersistence.get())
- },
- async clearWallets (): Promise {
- await WalletPersistence.set([])
- setDataList(await WalletPersistence.get())
- }
- }
-
- return (
-
- {props.children}
-
- )
-}
diff --git a/app/contexts/WalletPersistenceContext.tsx b/app/contexts/WalletPersistenceContext.tsx
new file mode 100644
index 0000000000..8d8ff3a665
--- /dev/null
+++ b/app/contexts/WalletPersistenceContext.tsx
@@ -0,0 +1,54 @@
+import React, { createContext, useContext, useEffect, useState } from 'react'
+import { Logging } from '../api'
+import { WalletPersistence, WalletPersistenceData } from '../api/wallet'
+import { useNetworkContext } from './NetworkContext'
+
+interface WalletPersistenceContextI {
+ wallets: Array>
+ /**
+ * @param {WalletPersistenceData} data to set, only 1 wallet is supported for now
+ */
+ setWallet: (data: WalletPersistenceData) => Promise
+ clearWallets: () => Promise
+}
+
+const WalletPersistenceContext = createContext(undefined as any)
+
+/**
+ * WalletManagement Context wrapped within
+ *
+ * This context enable wallet management by allow access to all configured wallets.
+ * Setting, removing and getting individual wallet.
+ */
+export function useWalletPersistenceContext (): WalletPersistenceContextI {
+ return useContext(WalletPersistenceContext)
+}
+
+export function WalletPersistenceProvider (props: React.PropsWithChildren): JSX.Element | null {
+ const { network } = useNetworkContext()
+ const [list, setList] = useState>>([])
+
+ useEffect(() => {
+ WalletPersistence.get().then(dataList => {
+ setList(dataList)
+ }).catch(Logging.error)
+ }, [network])
+
+ const management: WalletPersistenceContextI = {
+ wallets: list,
+ async setWallet (data: WalletPersistenceData): Promise {
+ await WalletPersistence.set([data])
+ setList(await WalletPersistence.get())
+ },
+ async clearWallets (): Promise {
+ await WalletPersistence.set([])
+ setList(await WalletPersistence.get())
+ }
+ }
+
+ return (
+
+ {props.children}
+
+ )
+}
diff --git a/app/screens/AppNavigator/screens/Settings/SettingsScreen.tsx b/app/screens/AppNavigator/screens/Settings/SettingsScreen.tsx
index a8748d285e..8d65f2ed2b 100644
--- a/app/screens/AppNavigator/screens/Settings/SettingsScreen.tsx
+++ b/app/screens/AppNavigator/screens/Settings/SettingsScreen.tsx
@@ -6,7 +6,7 @@ import { Alert, Platform, ScrollView, TouchableOpacity } from 'react-native'
import { Text } from '../../../../components'
import { SectionTitle } from '../../../../components/SectionTitle'
import { useNetworkContext } from '../../../../contexts/NetworkContext'
-import { useWalletManagementContext } from '../../../../contexts/WalletManagementContext'
+import { useWalletPersistenceContext } from '../../../../contexts/WalletPersistenceContext'
import { EnvironmentNetwork, getEnvironment, isPlayground } from '../../../../environment'
import { tailwind } from '../../../../tailwind'
import { translate } from '../../../../translations'
@@ -65,7 +65,7 @@ function RowNetworkItem (props: { network: EnvironmentNetwork }): JSX.Element {
}
function RowExitWalletItem (): JSX.Element {
- const { clearWallets } = useWalletManagementContext()
+ const { clearWallets } = useWalletPersistenceContext()
async function onExitWallet (): Promise {
if (Platform.OS === 'web') {
diff --git a/app/screens/PlaygroundNavigator/PlaygroundNavigator.tsx b/app/screens/PlaygroundNavigator/PlaygroundNavigator.tsx
index a280487177..2668b56ff1 100644
--- a/app/screens/PlaygroundNavigator/PlaygroundNavigator.tsx
+++ b/app/screens/PlaygroundNavigator/PlaygroundNavigator.tsx
@@ -1,6 +1,6 @@
import { createStackNavigator } from '@react-navigation/stack'
import React from 'react'
-import { HeaderFont } from '../../components/Text'
+import { HeaderFont } from '../../components'
import { PlaygroundScreen } from './PlaygroundScreen'
export interface PlaygroundParamList {
diff --git a/app/screens/PlaygroundNavigator/PlaygroundScreen.tsx b/app/screens/PlaygroundNavigator/PlaygroundScreen.tsx
index f1d2bd8ac0..0dfcc25ded 100644
--- a/app/screens/PlaygroundNavigator/PlaygroundScreen.tsx
+++ b/app/screens/PlaygroundNavigator/PlaygroundScreen.tsx
@@ -1,6 +1,8 @@
import React from 'react'
import { ScrollView } from 'react-native'
import { Text, View } from '../../components'
+import { WalletProvider } from '../../contexts/WalletContext'
+import { useWalletPersistenceContext } from '../../contexts/WalletPersistenceContext'
import { tailwind } from '../../tailwind'
import { PlaygroundConnection } from './sections/PlaygroundConnection'
import { PlaygroundToken } from './sections/PlaygroundToken'
@@ -25,6 +27,20 @@ export function PlaygroundScreen (): JSX.Element {
+
+
+ )
+}
+
+function PlaygroundWalletSection (): JSX.Element | null {
+ const { wallets } = useWalletPersistenceContext()
+
+ if (wallets.length === 0) {
+ return null
+ }
+
+ return (
+
@@ -32,6 +48,6 @@ export function PlaygroundScreen (): JSX.Element {
-
+
)
}
diff --git a/app/screens/PlaygroundNavigator/sections/PlaygroundToken.tsx b/app/screens/PlaygroundNavigator/sections/PlaygroundToken.tsx
index f5c787a4dd..5170ba63bc 100644
--- a/app/screens/PlaygroundNavigator/sections/PlaygroundToken.tsx
+++ b/app/screens/PlaygroundNavigator/sections/PlaygroundToken.tsx
@@ -3,13 +3,13 @@ import { PlaygroundRpcClient } from '@defichain/playground-api-client'
import React, { useEffect, useState } from 'react'
import { Text, View } from '../../../components'
import { usePlaygroundContext } from '../../../contexts/PlaygroundContext'
-import { useWalletManagementContext } from '../../../contexts/WalletManagementContext'
+import { useWallet } from '../../../contexts/WalletContext'
import { tailwind } from '../../../tailwind'
import { PlaygroundAction } from '../components/PlaygroundAction'
import { PlaygroundStatus } from '../components/PlaygroundStatus'
export function PlaygroundToken (): JSX.Element | null {
- const { wallets } = useWalletManagementContext()
+ const wallet = useWallet()
const { rpc, api } = usePlaygroundContext()
const [status, setStatus] = useState('loading')
const [tokens, setTokens] = useState([])
@@ -23,10 +23,6 @@ export function PlaygroundToken (): JSX.Element | null {
})
}, [])
- if (wallets.length === 0) {
- return null
- }
-
const actions = tokens.filter(({ symbol }) => symbol !== 'DFI').map(token => {
return (
{
- const address = await wallets[0].get(0).getAddress()
+ const address = await wallet.get(0).getAddress()
await rpc.call('sendtokenstoaddress', [{}, {
[address]: `10@${token.symbol}`
}], 'number')
@@ -62,7 +58,7 @@ export function PlaygroundToken (): JSX.Element | null {
onPress={async () => {
await api.wallet.sendTokenDfiToAddress({
amount: '10',
- address: await wallets[0].get(0).getAddress()
+ address: await wallet.get(0).getAddress()
})
}}
/>
diff --git a/app/screens/PlaygroundNavigator/sections/PlaygroundUTXO.tsx b/app/screens/PlaygroundNavigator/sections/PlaygroundUTXO.tsx
index 7b58ae4923..48a013e116 100644
--- a/app/screens/PlaygroundNavigator/sections/PlaygroundUTXO.tsx
+++ b/app/screens/PlaygroundNavigator/sections/PlaygroundUTXO.tsx
@@ -1,13 +1,13 @@
import React, { useEffect, useState } from 'react'
import { Text, View } from '../../../components'
import { usePlaygroundContext } from '../../../contexts/PlaygroundContext'
-import { useWalletManagementContext } from '../../../contexts/WalletManagementContext'
+import { useWallet } from '../../../contexts/WalletContext'
import { tailwind } from '../../../tailwind'
import { PlaygroundAction } from '../components/PlaygroundAction'
import { PlaygroundStatus } from '../components/PlaygroundStatus'
-export function PlaygroundUTXO (): JSX.Element | null {
- const { wallets } = useWalletManagementContext()
+export function PlaygroundUTXO (): JSX.Element {
+ const wallet = useWallet()
const { api, rpc } = usePlaygroundContext()
const [status, setStatus] = useState('loading')
@@ -19,21 +19,6 @@ export function PlaygroundUTXO (): JSX.Element | null {
})
}, [])
- if (wallets.length === 0) {
- return null
- }
-
- const actions = status === 'online' ? (
- {
- const address = await wallets[0].get(0).getAddress()
- await rpc.wallet.sendToAddress(address, 10)
- }}
- />
- ) : null
-
return (
@@ -47,7 +32,16 @@ export function PlaygroundUTXO (): JSX.Element | null {
- {actions}
+ {status === 'online' ? (
+ {
+ const address = await wallet.get(0).getAddress()
+ await rpc.wallet.sendToAddress(address, 10)
+ }}
+ />
+ ) : null}
)
}
diff --git a/app/screens/PlaygroundNavigator/sections/PlaygroundWallet.tsx b/app/screens/PlaygroundNavigator/sections/PlaygroundWallet.tsx
index f156ad1a1d..ad2f26f9b2 100644
--- a/app/screens/PlaygroundNavigator/sections/PlaygroundWallet.tsx
+++ b/app/screens/PlaygroundNavigator/sections/PlaygroundWallet.tsx
@@ -2,10 +2,10 @@ import { generateMnemonicWords } from '@defichain/jellyfish-wallet-mnemonic'
import * as Random from 'expo-random'
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
-import { MnemonicUnprotected } from '../../../api/wallet/provider/mnemonic_unprotected'
+import { MnemonicUnprotected } from '../../../api/wallet'
import { Text, View } from '../../../components'
import { useNetworkContext } from '../../../contexts/NetworkContext'
-import { useWalletManagementContext } from '../../../contexts/WalletManagementContext'
+import { useWalletPersistenceContext } from '../../../contexts/WalletPersistenceContext'
import { useWhaleApiClient } from '../../../contexts/WhaleContext'
import { fetchTokens } from '../../../hooks/wallet/TokensAPI'
import { RootState } from '../../../store'
@@ -14,7 +14,7 @@ import { PlaygroundAction } from '../components/PlaygroundAction'
import { PlaygroundStatus } from '../components/PlaygroundStatus'
export function PlaygroundWallet (): JSX.Element | null {
- const { wallets, clearWallets, setWallet } = useWalletManagementContext()
+ const { wallets, clearWallets, setWallet } = useWalletPersistenceContext()
const network = useNetworkContext()
const whaleApiClient = useWhaleApiClient()
const dispatch = useDispatch()
diff --git a/app/screens/RootNavigator.tsx b/app/screens/RootNavigator.tsx
index ea1dfbc02a..779f261b6d 100644
--- a/app/screens/RootNavigator.tsx
+++ b/app/screens/RootNavigator.tsx
@@ -1,6 +1,9 @@
-import React from 'react'
-import { WalletProvider } from '../contexts/WalletContext'
-import { useWalletManagementContext } from '../contexts/WalletManagementContext'
+import React, { PropsWithChildren, useEffect, useState } from 'react'
+import { useDispatch } from 'react-redux'
+import { Logging } from '../api'
+import { useWallet, WalletProvider } from '../contexts/WalletContext'
+import { useWalletPersistenceContext } from '../contexts/WalletPersistenceContext'
+import { wallet as store } from '../store/wallet'
import { AppNavigator } from './AppNavigator/AppNavigator'
import { WalletNavigator } from './WalletNavigator/WalletNavigator'
@@ -8,15 +11,40 @@ import { WalletNavigator } from './WalletNavigator/WalletNavigator'
* Top Root Level Wallet State to control what screen to show
*/
export function RootNavigator (): JSX.Element {
- const { wallets } = useWalletManagementContext()
+ const { wallets } = useWalletPersistenceContext()
if (wallets.length === 0) {
return
}
return (
-
-
+
+
+
+
)
}
+
+/**
+ * TODO(fuxingloh): to deprecate completely
+ * @deprecated included for legacy reasons, moving forward address should not be set in store
+ */
+function WalletAddressProvider (props: PropsWithChildren): JSX.Element | null {
+ const wallet = useWallet()
+ const dispatch = useDispatch()
+ const [isLoaded, setLoaded] = useState(false)
+
+ useEffect(() => {
+ wallet.get(0).getAddress().then(address => {
+ dispatch(store.actions.setAddress(address))
+ setLoaded(true)
+ }).catch(Logging.error)
+ }, [wallet])
+
+ if (!isLoaded) {
+ return null
+ }
+
+ return props.children
+}
diff --git a/app/screens/WalletNavigator/screens/CreateWallet/VerifyMnemonicWallet.tsx b/app/screens/WalletNavigator/screens/CreateWallet/VerifyMnemonicWallet.tsx
index e7eca04e08..c642b31dbe 100644
--- a/app/screens/WalletNavigator/screens/CreateWallet/VerifyMnemonicWallet.tsx
+++ b/app/screens/WalletNavigator/screens/CreateWallet/VerifyMnemonicWallet.tsx
@@ -5,7 +5,7 @@ import { KeyboardAvoidingView, ScrollView, TouchableOpacity } from 'react-native
import { MnemonicUnprotected } from '../../../../api/wallet/provider/mnemonic_unprotected'
import { Text, TextInput, View } from '../../../../components'
import { useNetworkContext } from '../../../../contexts/NetworkContext'
-import { useWalletManagementContext } from '../../../../contexts/WalletManagementContext'
+import { useWalletPersistenceContext } from '../../../../contexts/WalletPersistenceContext'
import { tailwind } from '../../../../tailwind'
import { WalletParamList } from '../../WalletNavigator'
@@ -17,7 +17,7 @@ export function VerifyMnemonicWallet ({ route }: Props): JSX.Element {
const [valid, setValid] = useState(true)
const { network } = useNetworkContext()
- const { setWallet } = useWalletManagementContext()
+ const { setWallet } = useWalletPersistenceContext()
async function onVerify (): Promise {
if (actualWords.join(' ') === enteredWords.join(' ')) {
diff --git a/app/screens/WalletNavigator/screens/RestoreWallet/RestoreMnemonicWallet.tsx b/app/screens/WalletNavigator/screens/RestoreWallet/RestoreMnemonicWallet.tsx
index 3254ca74ff..3a08bc339d 100644
--- a/app/screens/WalletNavigator/screens/RestoreWallet/RestoreMnemonicWallet.tsx
+++ b/app/screens/WalletNavigator/screens/RestoreWallet/RestoreMnemonicWallet.tsx
@@ -9,14 +9,14 @@ import { Text, View } from '../../../../components'
import { Button } from '../../../../components/Button'
import { SectionTitle } from '../../../../components/SectionTitle'
import { useNetworkContext } from '../../../../contexts/NetworkContext'
-import { useWalletManagementContext } from '../../../../contexts/WalletManagementContext'
+import { useWalletPersistenceContext } from '../../../../contexts/WalletPersistenceContext'
import { tailwind } from '../../../../tailwind'
import { translate } from '../../../../translations'
import LoadingScreen from '../../../LoadingNavigator/LoadingScreen'
export function RestoreMnemonicWallet (): JSX.Element {
const { network } = useNetworkContext()
- const { setWallet } = useWalletManagementContext()
+ const { setWallet } = useWalletPersistenceContext()
const { control, formState: { isValid }, getValues } = useForm({ mode: 'onChange' })
const [recoveryWords] = useState(Array.from(Array(24), (v, i) => i + 1))
const [isSubmitting, setIsSubmitting] = useState(false)
diff --git a/app/screens/WalletNavigator/screens/components/OnboardingCarousel.tsx b/app/screens/WalletNavigator/screens/components/OnboardingCarousel.tsx
index 630569afb9..13a42b0e0c 100644
--- a/app/screens/WalletNavigator/screens/components/OnboardingCarousel.tsx
+++ b/app/screens/WalletNavigator/screens/components/OnboardingCarousel.tsx
@@ -7,7 +7,7 @@ import ImageB from '../../../../assets/images/onboarding/b.png'
import ImageC from '../../../../assets/images/onboarding/c.png'
import { Text, View } from '../../../../components'
import { AppIcon } from '../../../../components/icons/AppIcon'
-import { useWalletManagementContext } from '../../../../contexts/WalletManagementContext'
+import { useWalletPersistenceContext } from '../../../../contexts/WalletPersistenceContext'
import { getEnvironment } from '../../../../environment'
import { tailwind } from '../../../../tailwind'
import { translate } from '../../../../translations'
@@ -39,7 +39,7 @@ const slides: JSX.Element[] = [,
const { width } = Platform.OS === 'web' ? { width: '375px' } : Dimensions.get('window')
export function InitialSlide (): JSX.Element {
- const { setWallet } = useWalletManagementContext()
+ const { setWallet } = useWalletPersistenceContext()
const onDebugPress = getEnvironment().debug ? async () => {
await setWallet(MnemonicUnprotected.Abandon23Playground)
} : undefined
diff --git a/app/store/wallet.ts b/app/store/wallet.ts
index b306a6d7a7..9c07271d84 100644
--- a/app/store/wallet.ts
+++ b/app/store/wallet.ts
@@ -10,6 +10,9 @@ export interface WalletToken extends AddressToken {
export interface WalletState {
utxoBalance: string
tokens: WalletToken[]
+ /**
+ * @deprecated use `useWalletContext().get(0).getAddress()` instead
+ */
address: string
}
diff --git a/package-lock.json b/package-lock.json
index 9376f046d0..7483279dbc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"@defichain/jellyfish-transaction": ">=0.33.0",
"@defichain/jellyfish-transaction-builder": ">=0.33.0",
"@defichain/jellyfish-wallet": ">=0.33.0",
+ "@defichain/jellyfish-wallet-encrypted": ">=0.33.0",
"@defichain/jellyfish-wallet-mnemonic": ">=0.33.0",
"@defichain/playground-api-client": ">=0.7.0",
"@defichain/whale-api-client": ">=0.7.0",
@@ -2120,6 +2121,15 @@
"bignumber.js": "^9.0.1"
}
},
+ "node_modules/@defichain/jellyfish-wallet-encrypted": {
+ "version": "0.33.0",
+ "resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet-encrypted/-/jellyfish-wallet-encrypted-0.33.0.tgz",
+ "integrity": "sha512-HDgGl30xCIPx9E1efRF3d4n8MlhlbpJ2DGAnJUM9fOlXTtp9T0ihhFek8wqNOtj7hP6Y9H8ANW+KcuA4XwoTUA==",
+ "dependencies": {
+ "@defichain/jellyfish-wallet-mnemonic": "^0.33.0",
+ "scrypt-js": "^3.0.1"
+ }
+ },
"node_modules/@defichain/jellyfish-wallet-mnemonic": {
"version": "0.33.0",
"resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet-mnemonic/-/jellyfish-wallet-mnemonic-0.33.0.tgz",
@@ -33297,6 +33307,11 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/scrypt-js": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz",
+ "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA=="
+ },
"node_modules/select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -42133,6 +42148,15 @@
"@defichain/jellyfish-transaction": "^0.33.0"
}
},
+ "@defichain/jellyfish-wallet-encrypted": {
+ "version": "0.33.0",
+ "resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet-encrypted/-/jellyfish-wallet-encrypted-0.33.0.tgz",
+ "integrity": "sha512-HDgGl30xCIPx9E1efRF3d4n8MlhlbpJ2DGAnJUM9fOlXTtp9T0ihhFek8wqNOtj7hP6Y9H8ANW+KcuA4XwoTUA==",
+ "requires": {
+ "@defichain/jellyfish-wallet-mnemonic": "^0.33.0",
+ "scrypt-js": "^3.0.1"
+ }
+ },
"@defichain/jellyfish-wallet-mnemonic": {
"version": "0.33.0",
"resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet-mnemonic/-/jellyfish-wallet-mnemonic-0.33.0.tgz",
@@ -61017,6 +61041,7 @@
"resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.59.0.tgz",
"integrity": "sha512-1O3wrnMq4NcPQ1asEcl9lRDn/t+F1Oef6S9WaYVIKEhg9m/EQRGVrrTVP+R6B5Eeaj3+zNKbzM8Dx/NWy1hUbQ==",
"requires": {
+ "@babel/core": "^7.0.0",
"babel-preset-fbjs": "^3.3.0",
"metro-babel-transformer": "0.59.0",
"metro-react-native-babel-preset": "0.59.0",
@@ -66721,6 +66746,11 @@
"ajv-keywords": "^3.5.2"
}
},
+ "scrypt-js": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz",
+ "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA=="
+ },
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
diff --git a/package.json b/package.json
index e24ef7d948..60204349b6 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"@defichain/jellyfish-transaction": ">=0.33.0",
"@defichain/jellyfish-transaction-builder": ">=0.33.0",
"@defichain/jellyfish-wallet": ">=0.33.0",
+ "@defichain/jellyfish-wallet-encrypted": ">=0.33.0",
"@defichain/jellyfish-wallet-mnemonic": ">=0.33.0",
"@defichain/playground-api-client": ">=0.7.0",
"@defichain/whale-api-client": ">=0.7.0",