on 4b0ca21 help sign in
bridge/src/store/wallet.js
192 lines 4.9 kB history raw
1import React, {
2 createContext,
3 forwardRef,
4 useCallback,
5 useContext,
6 useState,
7 useEffect,
8} from 'react';
9import { Just, Nothing } from 'folktale/maybe';
10import { includes } from 'lodash';
12import { walletFromMnemonic } from 'lib/wallet';
13import {
14 DEFAULT_HD_PATH,
15 NONCUSTODIAL_WALLETS,
16 WALLET_TYPES,
17} from 'lib/constants';
18import { getAuthToken } from 'lib/authToken';
19import { BRIDGE_ERROR } from 'lib/error';
21import { useNetwork } from 'store/network';
22import { publicToAddress } from 'lib/utils/address';
24export const WalletContext = createContext(null);
26const DEFAULT_WALLET_TYPE = WALLET_TYPES.TICKET;
28// NB (jtobin):
29//
30// Note that the 'wallet' prop has type depending on the 'walletType' prop.
31// These could be bound together in a single structure (so that
32// 'walletType' acted more explicitly as a data constructor of sorts) but
33// it doesn't necessarily help us much, since we branch on 'walletType'
34// before setting 'wallet'.
35//
36// Wallets are always wrapped in For most authentication
37// mechanisms, Maybe wraps a BIP32 HD wallet; for Ethereum private keys,
38// JSON keystore files, and Metamask authentication, it wraps an
39// 'EthereumWallet'.
40function _useWallet(initialWallet = Nothing(), initialMnemonic = Nothing()) {
41 const [walletType, _setWalletType] = useState(() =>
42 initialMnemonic.matchWith({
43 Nothing: () => DEFAULT_WALLET_TYPE,
44 Just: () => WALLET_TYPES.MNEMONIC,
45 })
46 );
47 const [walletHdPath, setWalletHdPath] = useState(DEFAULT_HD_PATH);
48 const [wallet, _setWallet] = useState(initialWallet);
49 const [urbitWallet, _setUrbitWallet] = useState(Nothing());
50 const [authMnemonic, setAuthMnemonic] = useState(initialMnemonic);
51 const [networkSeed, setNetworkSeed] = useState(Nothing());
52 const [networkRevision, setNetworkRevision] = useState(Nothing());
54 const [authToken, setAuthToken] = useState(Nothing());
56 const { web3 } = useNetwork();
58 useEffect(() => {
59 (async () => {
60 if (
61 !Just.hasInstance(wallet) ||
62 !Just.hasInstance(web3) ||
63 NONCUSTODIAL_WALLETS.has(walletType)
64 ) {
65 return;
66 }
68 const _wallet = wallet.value;
69 const _web3 = web3.value;
70 const token = await getAuthToken({
71 wallet: _wallet,
72 walletType,
73 walletHdPath,
74 web3: _web3,
75 });
77 setAuthToken(Just(token));
78 })();
79 }, [wallet, walletType, walletHdPath, web3]);
81 const setWalletType = useCallback(
82 walletType => {
83 if (!includes(WALLET_TYPES, walletType)) {
84 throw new Error(BRIDGE_ERROR.INVALID_WALLET_TYPE);
85 }
87 _setWalletType(walletType);
88 },
89 [_setWalletType]
90 );
92 const setWallet = useCallback(
93 wallet => {
94 // force that public addresses are derived for each wallet
95 // NOTE wallet is Maybe<> and .map is Maybe#map
96 wallet.map(wal => {
97 wal.address = wal.address || publicToAddress(wal.publicKey);
98 return wal;
99 });
101 _setWallet(wallet);
102 },
103 [_setWallet]
104 );
106 const setUrbitWallet = useCallback(
107 urbitWallet => {
108 if (Just.hasInstance(urbitWallet)) {
109 // when an urbit wallet is set, also derive
110 // a normal bip32 wallet using the ownership address
111 const wallet = walletFromMnemonic(
112 urbitWallet.value.ownership.seed,
113 DEFAULT_HD_PATH,
114 urbitWallet.value.meta.passphrase
115 );
117 setWallet(wallet);
118 } else {
119 setWallet(Nothing());
120 }
122 _setUrbitWallet(urbitWallet);
123 },
124 [setWallet]
125 );
127 const resetWallet = useCallback(() => {
128 _setWalletType(DEFAULT_WALLET_TYPE);
129 setWalletHdPath(DEFAULT_HD_PATH);
130 _setWallet(Nothing());
131 _setUrbitWallet(Nothing());
132 setAuthMnemonic(Nothing());
133 setNetworkSeed(Nothing());
134 setNetworkRevision(Nothing());
135 }, [
136 _setWalletType,
137 setWalletHdPath,
138 _setWallet,
139 _setUrbitWallet,
140 setAuthMnemonic,
141 setNetworkSeed,
142 setNetworkRevision,
143 ]);
145 return {
146 //
147 walletType,
148 setWalletType,
149 //
150 walletHdPath,
151 setWalletHdPath,
152 //
153 wallet,
154 setWallet,
155 //
156 urbitWallet,
157 setUrbitWallet,
158 authMnemonic,
159 setAuthMnemonic,
160 //
161 networkSeed,
162 setNetworkSeed,
163 networkRevision,
164 setNetworkRevision,
165 //
166 resetWallet,
167 //
168 authToken,
169 setAuthToken,
170 };
173export function WalletProvider({ initialWallet, initialMnemonic, children }) {
174 const wallet = _useWallet(initialWallet, initialMnemonic);
176 return (
177 <WalletContext.Provider value={wallet}>{children}</WalletContext.Provider>
178 );
181// Hook version
182export function useWallet() {
183 return useContext(WalletContext);
186// HOC version
187export const withWallet = Component =>
188 forwardRef((props, ref) => (
189 <WalletContext.Consumer>
190 {wallet => <Component ref={ref} {...wallet} {...props} />}
191 </WalletContext.Consumer>
192 ));