Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#351 - WalletProvider refactor to move init logic into contexts/*.tsx #380

Merged
merged 58 commits into from
Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
f0d0bfe
quick save
Jul 22, 2021
1a25c4d
completed create pin page
Jul 22, 2021
e584da4
quick save
Jul 23, 2021
ae9fa64
Merge branch 'main' into ivan/pin-passphrase-components
Jul 23, 2021
3d7e31d
complete pin creations UI implementation
Jul 23, 2021
e3d96be
update OceanInterface queue api
Jul 23, 2021
08f8f75
update unit test
Jul 23, 2021
216d0d8
fix outdated jellyfish mnemonic usage
Jul 23, 2021
87e0176
derive account from wallet context when only needed
Jul 23, 2021
57a1888
add wallet context mock for oceaninterface unit test
Jul 23, 2021
a44f76a
fix test, redux store auto append broadcast status on queue
Jul 23, 2021
207753c
Merge remote-tracking branch 'origin/main' into ivan/refactor/ocean-i…
Jul 23, 2021
d8e70ca
Merge branch 'ivan/pin-passphrase-components' into ivan/refactor/ocea…
Jul 23, 2021
46ec1cf
install rn scrypt, implement native ScryptProvider
Jul 23, 2021
c2986ac
quick save
Jul 27, 2021
8b66afc
Merge branch 'main' into ivan/mnemonic-encryption-integration
Jul 27, 2021
79d1b4a
add custom max-w tailwind
Jul 27, 2021
9001e48
add delay for pin input callback, allow render before complete (if an…
Jul 27, 2021
c723f9e
delete accident swp
Jul 27, 2021
a870b72
fix merge, migrate to new custom button
Jul 27, 2021
95f26ea
done deferred prompt promise (UI thread resolve context init promise)
Jul 27, 2021
44bfdac
Merge branch 'main' into ivan/mnemonic-encryption-integration
Jul 27, 2021
72c35e2
make standalone passcode prompt "page" rendered side by side with mai…
Jul 27, 2021
ba8c29e
remove pininput in oceaninterface
Jul 27, 2021
473f1bd
Merge branch 'main' into ivan/mnemonic-encryption-integration
Jul 28, 2021
c428fe2
quick save
Jul 28, 2021
6ca5f00
completed encrypted wallet implementation (refactored)
Jul 28, 2021
7b9c7c4
syntax and comment fixes
Jul 28, 2021
29fab17
Merge branch 'main' into ivan/mnemonic-encryption-integration
Jul 28, 2021
b575ed0
rename scrypt native module file, to build correctly
Jul 29, 2021
7651b74
rename
Jul 29, 2021
627bf8b
added loading after collect pin, before signing complete
Jul 29, 2021
b6be12b
fix test snapshot
Jul 29, 2021
98456b0
try manual select module (by platform.os) for bundling
Jul 29, 2021
2165182
require at runtime
Jul 29, 2021
391d04b
temp disable web scryptsy
Jul 29, 2021
ec5da2e
implement scryptsy for web locally, dep removed from jellyfish
Jul 29, 2021
227f59c
move pin creation screens under wallet/
Jul 29, 2021
5b71533
fix pin input not auto focused (race condition)
Jul 29, 2021
f4a470b
bump dep jellyfish-wallet-encrypted 0.31
Jul 29, 2021
da8e296
fix outdated redux action usage, move files
Jul 29, 2021
48e5b5b
test mobile build without sestate at onpinchange
Jul 29, 2021
f358b9c
manual select scryptsy (do not rely on extension)
Jul 29, 2021
7fa31da
mock scrypt
Jul 30, 2021
5642cf3
merge main
Jul 30, 2021
7e94c20
fix translate, replaceAll not working in RN
Jul 30, 2021
3e8ad1e
fix auth UI not get dismissed correctly when wipe wallet
Jul 30, 2021
bf12869
minor syntax update, prevent less than 6 digit pin fire callback
Jul 30, 2021
3c63cbf
rollback changes that I don't need for this refactoring
fuxingloh Jul 31, 2021
340b50e
revert root navigator
fuxingloh Jul 31, 2021
5bb0f0f
rename passcode_attempt.ts
fuxingloh Jul 31, 2021
1beb050
refactor WalletManagementContext.tsx to WalletPersistenceContext.tsx
fuxingloh Jul 31, 2021
f22e8f4
added deprecated notice for wallet state
fuxingloh Aug 1, 2021
572ebcf
moved wallet init logic to WalletContext.tsx
fuxingloh Aug 1, 2021
1993b10
fixed playground with new wallet context setup
fuxingloh Aug 1, 2021
766ff4e
Merge remote-tracking branch 'origin/main' into fuxingloh/scrypt
fuxingloh Aug 1, 2021
62f54e3
updated package-lock.json
fuxingloh Aug 1, 2021
773c589
update to support scrypt
fuxingloh Aug 1, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -41,11 +41,11 @@ export default function App (): JSX.Element | null {
<NetworkProvider>
<PlaygroundProvider>
<WhaleProvider>
<WalletManagementProvider>
<WalletPersistenceProvider>
<StoreProvider store={store}>
<Main />
</StoreProvider>
</WalletManagementProvider>
</WalletPersistenceProvider>
</WhaleProvider>
</PlaygroundProvider>
</NetworkProvider>
Expand Down
1 change: 0 additions & 1 deletion app/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './wallet/persistence'
export * from './storage'
export * from './logging'
Original file line number Diff line number Diff line change
@@ -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()
Expand All @@ -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<string> = {
version: "v1",
type: undefined as any,
raw: ""
}

expect(() => {
initWhaleWallet(data, network, client)
}).toThrow('wallet undefined not available')
})
21 changes: 21 additions & 0 deletions app/api/wallet/index.ts
Original file line number Diff line number Diff line change
@@ -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<WhaleWalletAccount, WalletHdNode>

export function initWhaleWallet (provider: WalletHdNodeProvider<WalletHdNode>, 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'
20 changes: 20 additions & 0 deletions app/api/wallet/passcode_attempt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { StorageAPI } from '../storage'

const KEY = 'PASSCODE_ATTEMPT.count'

async function get (): Promise<number> {
const str = await StorageAPI.getItem(KEY)
return str === undefined ? 0 : Number(str)
}

async function set (count: number): Promise<void> {
await StorageAPI.setItem(KEY, `${count}`)
}

/**
* Failed passcode input counter persistence layer
*/
export const PasscodeAttemptCounter = {
set,
get
}
3 changes: 2 additions & 1 deletion app/api/wallet/persistence.ts
Original file line number Diff line number Diff line change
@@ -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<T> {
Expand Down
35 changes: 0 additions & 35 deletions app/api/wallet/provider/index.ts

This file was deleted.

51 changes: 51 additions & 0 deletions app/api/wallet/provider/mnemonic_encrypted.ts
Original file line number Diff line number Diff line change
@@ -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<EncryptedProviderData>,
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<WalletPersistenceData<EncryptedProviderData>> {
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')
}
97 changes: 77 additions & 20 deletions app/contexts/WalletContext.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,91 @@
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<WhaleWallet>(undefined as any)

export function useWallet (): WhaleWallet {
return useContext(WalletContext)
}

export function WalletProvider (props: React.PropsWithChildren<any>): JSX.Element | null {
const dispatch = useDispatch()
const management = useWalletManagementContext()
const wallet = management.wallets[0]

const [isLoaded, setLoaded] = useState(false)
interface WalletProviderProps<T> extends PropsWithChildren<any> {
data: WalletPersistenceData<T>
}

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<any>): JSX.Element | null {
if (props.data.type === WalletType.MNEMONIC_UNPROTECTED) {
return (
<MnemonicUnprotectedProvider {...props}>
{props.children}
</MnemonicUnprotectedProvider>
)
}

if (!isLoaded) {
return null
if (props.data.type === WalletType.MNEMONIC_ENCRYPTED) {
return (
<MnemonicEncryptedProvider {...props}>
{props.children}
</MnemonicEncryptedProvider>
)
}

throw new Error(`wallet type: ${props.data.type as string} not available`)
}

function MnemonicUnprotectedProvider (props: WalletProviderProps<MnemonicProviderData>): 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 (
<WalletContext.Provider value={wallet}>
{props.children}
</WalletContext.Provider>
)
}

function MnemonicEncryptedProvider (props: WalletProviderProps<EncryptedProviderData>): JSX.Element | null {
const { network } = useNetworkContext()
const client = useWhaleApiClient()
const navigation = useNavigation()

const promptPassphrase = useCallback(async () => {
return await new Promise<string>((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 (
<WalletContext.Provider value={wallet}>
{props.children}
Expand Down
61 changes: 0 additions & 61 deletions app/contexts/WalletManagementContext.tsx

This file was deleted.

Loading