on bc552c8 help sign in
bridge/src/store/wallet.js
151 lines 3.9 kB history raw
1import React, {
2 createContext,
3 forwardRef,
4 useCallback,
5 useContext,
6 useState,
7} from 'react';
8import { Just, Nothing } from 'folktale/maybe';
9import { includes } from 'lodash';
11import {
12 WALLET_TYPES,
13 DEFAULT_HD_PATH,
14 addressFromSecp256k1Public,
15 walletFromMnemonic,
16} from 'lib/wallet';
17import { BRIDGE_ERROR } from 'lib/error';
19export const WalletContext = createContext(null);
21const DEFAULT_WALLET_TYPE = WALLET_TYPES.TICKET;
23// NB (jtobin):
24//
25// Note that the 'wallet' prop has type depending on the 'walletType' prop.
26// These could be bound together in a single structure (so that
27// 'walletType' acted more explicitly as a data constructor of sorts) but
28// it doesn't necessarily help us much, since we branch on 'walletType'
29// before setting 'wallet'.
30//
31// Wallets are always wrapped in For most authentication
32// mechanisms, Maybe wraps a BIP32 HD wallet; for Ethereum private keys,
33// JSON keystore files, and Metamask authentication, it wraps an
34// 'EthereumWallet'.
35function _useWallet(initialWallet = Nothing(), initialMnemonic = Nothing()) {
36 const [walletType, _setWalletType] = useState(DEFAULT_WALLET_TYPE);
37 const [walletHdPath, setWalletHdPath] = useState(DEFAULT_HD_PATH);
38 const [wallet, _setWallet] = useState(initialWallet);
39 const [urbitWallet, _setUrbitWallet] = useState(Nothing());
40 const [authMnemonic, setAuthMnemonic] = useState(initialMnemonic);
41 const [networkSeed, setNetworkSeed] = useState(Nothing());
42 const [networkRevision, setNetworkRevision] = useState(Nothing());
44 const setWalletType = useCallback(
45 walletType => {
46 if (!includes(WALLET_TYPES, walletType)) {
47 throw BRIDGE_ERROR.INVALID_WALLET_TYPE;
48 }
50 _setWalletType(walletType);
51 },
52 [_setWalletType]
53 );
55 const setWallet = useCallback(
56 wallet => {
57 // force that public addresses are derived for each wallet
58 wallet.map(wal => {
59 wal.address = wal.address || addressFromSecp256k1Public(wal.publicKey);
60 return wal;
61 });
63 _setWallet(wallet);
64 },
65 [_setWallet]
66 );
68 const setUrbitWallet = useCallback(
69 urbitWallet => {
70 if (Just.hasInstance(urbitWallet)) {
71 // when an urbit wallet is set, also derive
72 // a normal bip32 wallet using the ownership address
73 const wallet = walletFromMnemonic(
74 urbitWallet.value.ownership.seed,
75 DEFAULT_HD_PATH,
76 urbitWallet.value.meta.passphrase
77 );
79 setWallet(wallet);
80 } else {
81 setWallet(Nothing());
82 }
84 _setUrbitWallet(urbitWallet);
85 },
86 [setWallet]
87 );
89 const resetWallet = useCallback(() => {
90 _setWalletType(DEFAULT_WALLET_TYPE);
91 setWalletHdPath(DEFAULT_HD_PATH);
92 _setWallet(Nothing());
93 _setUrbitWallet(Nothing());
94 setAuthMnemonic(Nothing());
95 setNetworkSeed(Nothing());
96 setNetworkRevision(Nothing());
97 }, [
98 _setWalletType,
99 setWalletHdPath,
100 _setWallet,
101 _setUrbitWallet,
102 setAuthMnemonic,
103 setNetworkSeed,
104 setNetworkRevision,
105 ]);
107 return {
108 //
109 walletType,
110 setWalletType,
111 //
112 walletHdPath,
113 setWalletHdPath,
114 //
115 wallet,
116 setWallet,
117 //
118 urbitWallet,
119 setUrbitWallet,
120 authMnemonic,
121 setAuthMnemonic,
122 //
123 networkSeed,
124 setNetworkSeed,
125 networkRevision,
126 setNetworkRevision,
127 //
128 resetWallet,
129 };
132export function WalletProvider({ initialWallet, initialMnemonic, children }) {
133 const wallet = _useWallet(initialWallet, initialMnemonic);
135 return (
136 <WalletContext.Provider value={wallet}>{children}</WalletContext.Provider>
137 );
140// Hook version
141export function useWallet() {
142 return useContext(WalletContext);
145// HOC version
146export const withWallet = Component =>
147 forwardRef((props, ref) => (
148 <WalletContext.Consumer>
149 {wallet => <Component ref={ref} {...wallet} {...props} />}
150 </WalletContext.Consumer>
151 ));