on c19b2a8 help sign in
bridge/src/store/wallet.js
157 lines 4.1 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(() =>
37 initialMnemonic.matchWith({
38 Nothing: () => DEFAULT_WALLET_TYPE,
39 Just: () => WALLET_TYPES.MNEMONIC,
40 })
41 );
42 const [walletHdPath, setWalletHdPath] = useState(DEFAULT_HD_PATH);
43 const [wallet, _setWallet] = useState(initialWallet);
44 const [urbitWallet, _setUrbitWallet] = useState(Nothing());
45 const [authMnemonic, setAuthMnemonic] = useState(initialMnemonic);
46 const [networkSeed, setNetworkSeed] = useState(Nothing());
47 const [networkRevision, setNetworkRevision] = useState(Nothing());
49 const setWalletType = useCallback(
50 walletType => {
51 if (!includes(WALLET_TYPES, walletType)) {
52 throw new Error(BRIDGE_ERROR.INVALID_WALLET_TYPE);
53 }
55 _setWalletType(walletType);
56 },
57 [_setWalletType]
58 );
60 const setWallet = useCallback(
61 wallet => {
62 // force that public addresses are derived for each wallet
63 // NOTE wallet is Maybe<> and .map is Maybe#map
64 wallet.map(wal => {
65 wal.address = wal.address || addressFromSecp256k1Public(wal.publicKey);
66 return wal;
67 });
69 _setWallet(wallet);
70 },
71 [_setWallet]
72 );
74 const setUrbitWallet = useCallback(
75 urbitWallet => {
76 if (Just.hasInstance(urbitWallet)) {
77 // when an urbit wallet is set, also derive
78 // a normal bip32 wallet using the ownership address
79 const wallet = walletFromMnemonic(
80 urbitWallet.value.ownership.seed,
81 DEFAULT_HD_PATH,
82 urbitWallet.value.meta.passphrase
83 );
85 setWallet(wallet);
86 } else {
87 setWallet(Nothing());
88 }
90 _setUrbitWallet(urbitWallet);
91 },
92 [setWallet]
93 );
95 const resetWallet = useCallback(() => {
96 _setWalletType(DEFAULT_WALLET_TYPE);
97 setWalletHdPath(DEFAULT_HD_PATH);
98 _setWallet(Nothing());
99 _setUrbitWallet(Nothing());
100 setAuthMnemonic(Nothing());
101 setNetworkSeed(Nothing());
102 setNetworkRevision(Nothing());
103 }, [
104 _setWalletType,
105 setWalletHdPath,
106 _setWallet,
107 _setUrbitWallet,
108 setAuthMnemonic,
109 setNetworkSeed,
110 setNetworkRevision,
111 ]);
113 return {
114 //
115 walletType,
116 setWalletType,
117 //
118 walletHdPath,
119 setWalletHdPath,
120 //
121 wallet,
122 setWallet,
123 //
124 urbitWallet,
125 setUrbitWallet,
126 authMnemonic,
127 setAuthMnemonic,
128 //
129 networkSeed,
130 setNetworkSeed,
131 networkRevision,
132 setNetworkRevision,
133 //
134 resetWallet,
135 };
138export function WalletProvider({ initialWallet, initialMnemonic, children }) {
139 const wallet = _useWallet(initialWallet, initialMnemonic);
141 return (
142 <WalletContext.Provider value={wallet}>{children}</WalletContext.Provider>
143 );
146// Hook version
147export function useWallet() {
148 return useContext(WalletContext);
151// HOC version
152export const withWallet = Component =>
153 forwardRef((props, ref) => (
154 <WalletContext.Consumer>
155 {wallet => <Component ref={ref} {...wallet} {...props} />}
156 </WalletContext.Consumer>
157 ));