on master help sign in
feat: implement invite claiming tx, whole flow works
commit646840542fe639a162933686c61a693f0523a212 authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateThu 27 Jun 2019, 21:26 (7 years ago) parent4b25329
16 files changed+229−167
src/components/WarningBox.js+1−1 src/indigo-react/components/Typography.js+1−1 src/lib/invite.js+57−106 src/lib/timeout.js+1 src/lib/useResetPointCursor.js+12 src/views/Activate/ActivateDisclaimer.js+16−16 src/views/Activate/PassportTransfer.js+119−34 src/views/Activate/PassportVerify.js+5−7 src/views/InviteTicket.js+2−2 src/views/Login/Keystore.js+2 src/views/Login/Ledger.js+2 src/views/Login/Mnemonic.js+3 src/views/Login/PrivateKey.js+2 src/views/Login/Shards.js+2 src/views/Login/Ticket.js+2 src/views/Login/Trezor.js+2
src/components/WarningBox.js+1−1
@@ -5,7 +5,7 @@ import { Flex, Text } from 'indigo-react';
55export default function WarningBox({ className, children }) {
66 return (
77 <Flex className={cn('bg-red1 pv3 ph4', className)} align="center">
8− <Text className="f5 red3">{children}</Text>
8+ <Text className="f6 fw-bold red3">{children}</Text>
99 </Flex>
1010 );
1111}
src/indigo-react/components/Typography.js+1−1
@@ -14,7 +14,7 @@ export const H5 = typeWith('h5');
1414export const H6 = typeWith('h6');
1515export const Caption = typeWith('caption');
1616export const P = typeWith('p');
17−export const B = typeWith('b');
17+export const B = typeWith('b', 'fw-bold');
1818
1919export const Breadcrumb = typeWith('span', 'f6');
2020export const Text = typeWith('span');
src/lib/invite.js+57−106
@@ -1,4 +1,4 @@
1−import { Just, Nothing } from 'folktale/maybe';
1+import { Just } from 'folktale/maybe';
22import Tx from 'ethereumjs-tx';
33
44import * as azimuth from 'azimuth-js';
@@ -9,8 +9,7 @@ import * as tank from './tank';
99import JSZip from 'jszip';
1010import saveAs from 'file-saver';
1111
12−import { sendSignedTransaction } from './txn';
13−import { BRIDGE_ERROR } from './error';
12+import { sendSignedTransaction, hexify } from './txn';
1413import { attemptNetworkSeedDerivation } from './keys';
1514import { addHexPrefix, WALLET_TYPES } from './wallet';
1615
@@ -32,36 +31,36 @@ const WALLET_STATES = {
3231
3332const TRANSACTION_STATES = {
3433 GENERATING: {
35− label: 'Generating transactions',
36− pct: '0%',
34+ label: 'Generating Transactions...',
35+ progress: 0.0,
3736 },
3837 SIGNING: {
39− label: 'Signing transactions',
40− pct: '15%',
38+ label: 'Signing Transactions...',
39+ progress: 0.15,
4140 },
4241 FUNDING_INVITE: {
43− label: 'Funding invite wallet',
44− pct: '30%',
42+ label: 'Funding Invite Wallet...',
43+ progress: 0.3,
4544 },
4645 CLAIMING: {
47− label: 'Claiming invite',
48− pct: '55%',
46+ label: 'Claiming Invite...',
47+ progress: 0.55,
4948 },
5049 FUNDING_RECIPIENT: {
51− label: 'Funding recipient wallet',
52− pct: '65%',
50+ label: 'Funding Recipient Wallet...',
51+ progress: 0.65,
5352 },
5453 CONFIGURING: {
55− label: 'Configuring planet',
56− pct: '85%',
54+ label: 'Configuring Point...',
55+ progress: 0.85,
5756 },
5857 CLEANING: {
59− label: 'Cleaning up',
60− pct: '95%',
58+ label: 'Cleaning Up...',
59+ progress: 0.95,
6160 },
6261 DONE: {
6362 label: 'Done',
64− pct: '100%',
63+ progress: 1.0,
6564 },
6665};
6766
@@ -102,93 +101,61 @@ async function downloadWallet(paper) {
102101 });
103102}
104103
105−async function startTransactions(args) {
106− let {
107− realPointM,
108− web3: web3M,
109− contracts: contractsM,
110− inviteWalletM,
111− realWalletM,
112− setUrbitWallet,
113− updateProgress,
114− } = args;
115−
116− const askForFunding = (address, amount, current) => {
117− updateProgress({
118− type: 'notify',
119− value: `Please make sure ${address} has at least ${amount} wei, we'll continue once that's true. Current balance: ${current}. Waiting`,
104+async function claimPointFromInvite({
105+ inviteWallet,
106+ wallet,
107+ point,
108+ web3,
109+ contracts,
110+ onUpdate,
111+}) {
112+ const askForFunding = (address, minBalance, balance) =>
113+ onUpdate({
114+ type: 'askFunding',
115+ value: { address, minBalance, balance },
120116 });
121− };
122117
123− if (Nothing.hasInstance(web3M)) {
124− throw BRIDGE_ERROR.MISSING_WEB3;
125− }
126− const web3 = web3M.value;
127−
128− if (Nothing.hasInstance(contractsM)) {
129− throw BRIDGE_ERROR.MISSING_CONTRACTS;
130− }
131− const contracts = contractsM.value;
132−
133− if (Nothing.hasInstance(inviteWalletM)) {
134− throw BRIDGE_ERROR.MISSING_WALLET;
135− }
136− const inviteWallet = inviteWalletM.value;
137−
138− if (Nothing.hasInstance(realWalletM)) {
139− throw BRIDGE_ERROR.MISSING_WALLET;
140− }
141− const realWallet = realWalletM.value;
142−
143− // const realWallet = await urbitWalletFromTicket(args.realTicket, point);
144−
145− if (Nothing.hasInstance(realPointM)) {
146− throw BRIDGE_ERROR.MISSING_POINT;
147− }
148− const point = realPointM.value;
118+ const gotFunding = () => onUpdate({ type: 'gotFunding' });
119+ const progress = state => onUpdate({ type: 'progress', state });
149120
150121 const inviteAddress = inviteWallet.address;
151− console.log('working as', inviteAddress);
152122
153− // transfer from invite wallet to new wallet
123+ progress(TRANSACTION_STATES.GENERATING);
154124
155− let transferTx = azimuth.ecliptic.transferPoint(
125+ // transfer from invite wallet to new wallet
126+ const transferTx = azimuth.ecliptic.transferPoint(
156127 contracts,
157128 point,
158− realWallet.ownership.keys.address
129+ wallet.ownership.keys.address
159130 );
160131 transferTx.gas = 500000; //TODO can maybe be lower?
161132
162133 // ping gas tank with txs if needed
163−
164134 let inviteNonce = await web3.eth.getTransactionCount(inviteAddress);
165135 transferTx.nonce = inviteNonce++;
166136 transferTx.gasPrice = 20000000000; //NOTE we pay the premium for faster ux
167137 transferTx.from = inviteAddress;
168138
169− //NOTE using web3.eth.accounts.signTransaction is broken (1.0.0-beta51)
170− let transferStx = new Tx(transferTx);
139+ progress(TRANSACTION_STATES.SIGNING);
140+ // NOTE: using web3.eth.accounts.signTransaction is broken (1.0.0-beta51)
141+ const transferStx = new Tx(transferTx);
171142 transferStx.sign(inviteWallet.privateKey);
172− let rawTransferStx = '0x' + transferStx.serialize().toString('hex');
173−
143+ const rawTransferStx = hexify(transferStx.serialize());
174144 const transferCost = transferTx.gas * transferTx.gasPrice;
175− updateProgress({
176− type: 'progress',
177− value: TRANSACTION_STATES.FUNDING_INVITE,
178− });
145+
146+ progress(TRANSACTION_STATES.FUNDING_INVITE);
147+
179148 let usedTank = await tank.ensureFundsFor(
180149 web3,
181150 point,
182151 inviteAddress,
183152 transferCost,
184153 [rawTransferStx],
185− askForFunding
154+ askForFunding,
155+ gotFunding
186156 );
187157
188− updateProgress({
189− type: 'progress',
190− value: TRANSACTION_STATES.CLAIMING,
191− });
158+ progress(TRANSACTION_STATES.CLAIMING);
192159
193160 // send transaction
194161 await sendAndAwaitConfirm(web3, [Just(transferStx)], usedTank);
@@ -197,15 +164,13 @@ async function startTransactions(args) {
197164 // we're gonna be operating as the new wallet from here on out, so change
198165 // the relevant values
199166 //
200− setUrbitWallet(Just(realWallet));
201− const newAddress = realWallet.ownership.keys.address;
167+ const newAddress = wallet.ownership.keys.address;
202168
203169 // configure management proxy
204−
205− let managementTx = azimuth.ecliptic.setManagementProxy(
170+ const managementTx = azimuth.ecliptic.setManagementProxy(
206171 contracts,
207172 point,
208− realWallet.management.keys.address
173+ wallet.management.keys.address
209174 );
210175 managementTx.gas = 200000;
211176 managementTx.nonce = 0;
@@ -214,7 +179,7 @@ async function startTransactions(args) {
214179 //TODO feels like more of this logic should live in a lib?
215180 const seed = await attemptNetworkSeedDerivation(true, {
216181 walletType: WALLET_TYPES.TICKET,
217− urbitWallet: Just(realWallet),
182+ urbitWallet: Just(wallet),
218183 pointCursor: Just(point),
219184 pointCache: { [point]: { keyRevisionNumber: 0 } },
220185 });
@@ -251,17 +216,15 @@ async function startTransactions(args) {
251216
252217 let txPairs = txs.map(tx => {
253218 let stx = new Tx(tx);
254− stx.sign(Buffer.from(realWallet.ownership.keys.private, 'hex'));
219+ stx.sign(Buffer.from(wallet.ownership.keys.private, 'hex'));
255220 return {
256221 raw: '0x' + stx.serialize().toString('hex'),
257222 signed: stx,
258223 };
259224 });
260225
261− updateProgress({
262− type: 'progress',
263− value: TRANSACTION_STATES.FUNDING_RECIPIENT,
264− });
226+ progress(TRANSACTION_STATES.FUNDING_RECIPIENT);
227+
265228 usedTank = await tank.ensureFundsFor(
266229 web3,
267230 point,
@@ -271,17 +234,11 @@ async function startTransactions(args) {
271234 askForFunding
272235 );
273236
274− updateProgress({
275− type: 'progress',
276− value: TRANSACTION_STATES.CONFIGURING,
277− });
237+ progress(TRANSACTION_STATES.CONFIGURING);
278238
279239 await sendAndAwaitConfirm(web3, txPairs.map(p => Just(p.signed)), usedTank);
280240
281− updateProgress({
282− type: 'progress',
283− value: TRANSACTION_STATES.CLEANING,
284− });
241+ progress(TRANSACTION_STATES.CLEANING);
285242
286243 // if non-trivial eth left in invite wallet, transfer to new ownership
287244 let balance = await web3.eth.getBalance(inviteAddress);
@@ -300,20 +257,14 @@ async function startTransactions(args) {
300257 };
301258 let stx = new Tx(tx);
302259 stx.sign(inviteWallet.privateKey);
303− const rawTx = '0x' + stx.serialize().toString('hex');
260+ const rawTx = hexify(stx.serialize());
304261 web3.eth.sendSignedTransaction(rawTx).catch(err => {
305262 console.log('error sending value tx, who cares', err);
306263 });
307264 console.log('sent old balance');
308265 }
309266
310− updateProgress({
311− type: 'progress',
312− value: TRANSACTION_STATES.DONE,
313− });
314−
315− // proceed without waiting for confirm
316− setUrbitWallet(Just(realWallet));
267+ progress(TRANSACTION_STATES.DONE);
317268}
318269
319270async function sendAndAwaitConfirm(web3, signedTxs, usedTank) {
@@ -329,7 +280,7 @@ async function sendAndAwaitConfirm(web3, signedTxs, usedTank) {
329280export {
330281 generateWallet,
331282 downloadWallet,
332− startTransactions,
283+ claimPointFromInvite,
333284 INVITE_STAGES,
334285 WALLET_STATES,
335286 TRANSACTION_STATES,
src/lib/timeout.jsnew file+1
@@ -0,0 +1 @@
1+export default ms => new Promise(resolve => setTimeout(resolve, ms));
src/lib/useResetPointCursor.jsnew file+12
@@ -0,0 +1,12 @@
1+import { useEffect } from 'react';
2+import Maybe from 'folktale/maybe';
3+
4+import { usePointCursor } from 'store/pointCursor';
5+
6+export default function useResetPointCursor() {
7+ const { setPointCursor } = usePointCursor();
8+
9+ useEffect(() => {
10+ setPointCursor(Maybe.Nothing());
11+ }, [setPointCursor]);
12+}
src/views/Activate/ActivateDisclaimer.js+16−16
@@ -23,49 +23,49 @@ export default function ActivateDisclaimer() {
2323 Disclaimer
2424 </Grid.Item>
2525 <Grid.Item full>
26− <P>
26+ <Text className="f6 block mb4">
2727 Welcome to Bridge. Please read this information. Your assets could
2828 be stolen if you do not pay attention to these warnings.
29− </P>
29+ </Text>
3030
31− <P>
31+ <Text className="f6 block mb4">
3232 <B>You own and control your assets. We do not.</B> If you send your
3333 assets to another address, we can’t get them back for you.
34− </P>
34+ </Text>
3535
36− <B>Please understand that nobody can:</B>
37− <P>
36+ <B className="f6">Please understand that nobody can:</B>
37+ <Text className="f6 block mb4">
3838 1. Access your assets for you <br />
3939 2. Recover, reset, or modify ANY of your information <br />
4040 3. Reverse, cancel, or refund transactions <br />
4141 4. Hold, back-up, or access your keys
42− </P>
42+ </Text>
4343
44− <B>
44+ <B className="f6">
4545 You’re responsible for keeping your information safe. This includes:
4646 </B>
47− <P>
47+ <Text className="f6 block mb4">
4848 1. Private Keys/Mnemonic Phrases and passwords <br />
4949 2. JSON files <br />
5050 3. Hardware wallet PINs; <br />
5151 4. Downloading this software from a reliable site, and ensuring it
5252 has not been tampered with. [add something about using the checksum
5353 here]
54− </P>
54+ </Text>
5555
56− <B>To be clear</B>
57− <P>
56+ <B className="f6">To be clear</B>
57+ <Text className="f6 block">
5858 This software is provided “as is” without warranties of any kind and
5959 our liability to you in connection with the same is limited;
60− </P>
61− <P>
60+ </Text>
61+ <Text className="f6 block">
6262 We have no liability for any security problems or incidents that you
6363 may experience, including any loss or theft of your keys or any
6464 problems that may arise in connection with your wallet.
65− </P>
65+ </Text>
6666 </Grid.Item>
6767 <Grid.Item full as={WarningBox}>
68− Warning: We Can't Restore of Reset Your Master Ticket
68+ Warning: Nobody but you can restore or reset your Master Ticket
6969 </Grid.Item>
7070 <Grid.Item as={CheckboxInput} {...checkboxInput} full />
7171 <Grid.Item
src/views/Activate/PassportTransfer.js+119−34
@@ -1,64 +1,149 @@
1−import React, { useState, useEffect, useCallback } from 'react';
2−import Maybe from 'folktale/maybe';
3−import { Grid, H4, P, Text } from 'indigo-react';
4−import PaperCollateralRenderer from 'PaperCollateralRenderer';
1+import React, { useState, useCallback } from 'react';
2+import { Grid, H4, Text, ErrorText } from 'indigo-react';
3+
4+import { useNetwork } from 'store/network';
5+import { useWallet } from 'store/wallet';
6+import { useHistory } from 'store/history';
7+import { usePointCursor } from 'store/pointCursor';
58
69import * as need from 'lib/need';
7−import { useLocalRouter } from 'lib/LocalRouter';
10+import useLifecycle from 'lib/useLifecycle';
11+import { claimPointFromInvite } from 'lib/invite';
12+import timeout from 'lib/timeout';
13+import { fromWei } from 'lib/txn';
814
9−import { DownloadButton, ForwardButton } from 'components/Buttons';
1015import Steps from 'components/Steps';
11−
12−import { useActivateFlow } from './ActivateFlow';
13−import useLifecycle from 'lib/useLifecycle';
1416import WarningBox from 'components/WarningBox';
1517import LoadingBar from 'components/LoadingBar';
18+import Highlighted from 'components/Highlighted';
1619
17−const STATUS = {
18− CLAIMING: 'CLAIMING',
19− NETWORKING: 'NETWORKING',
20− REDIRECTING: 'REDIRECTING',
21−};
20+import { useActivateFlow } from './ActivateFlow';
2221
2322export default function PassportTransfer({ className }) {
23+ const { replaceWith, names } = useHistory();
24+ const { setUrbitWallet } = useWallet();
25+ const { setPointCursor } = usePointCursor();
26+ const { web3, contracts } = useNetwork();
2427 const { derivedWallet, derivedPoint, inviteWallet } = useActivateFlow();
25− const [status, setStatus] = useState(STATUS.CLAIMING);
26− const isClaiming = status === STATUS.CLAIMING;
28+ const [generalError, setGeneralError] = useState();
29+ const [{ label, progress }, setState] = useState({
30+ label: 'Verify Passport',
31+ progress: 0,
32+ });
33+ const [needFunds, setNeedFunds] = useState();
34+
35+ const goToLogin = useCallback(
36+ () =>
37+ replaceWith([
38+ { key: names.LANDING },
39+ { key: names.LOGIN },
40+ { key: names.POINTS },
41+ { key: names.POINT },
42+ ]),
43+ [replaceWith, names]
44+ );
45+
46+ const goToRestart = useCallback(
47+ () => replaceWith([{ key: names.LANDING }, { key: names.ACTIVATE }]),
48+ [replaceWith, names]
49+ );
2750
28− const titleText = (() => {
29− switch (status) {
30− case STATUS.CLAIMING:
31− return 'Claiming Point';
32− case STATUS.NETWORKING:
33− return 'Setting Networking Keys';
34− case STATUS.REDIRECTING:
35− return 'Transporting to Bridge';
36− default:
37− break;
51+ const handleUpdate = useCallback(
52+ ({ type, state, value }) => {
53+ switch (type) {
54+ case 'progress':
55+ return setState(state);
56+ case 'askFunding':
57+ return setNeedFunds(value);
58+ case 'gotFunding':
59+ return setNeedFunds(false);
60+ default:
61+ console.error(`Unknown update: ${type}`);
62+ }
63+ },
64+ [setState, setNeedFunds]
65+ );
66+
67+ const claimPoint = useCallback(async () => {
68+ const _inviteWallet = need.wallet(inviteWallet);
69+ const _wallet = need.wallet(derivedWallet);
70+ const _point = need.point(derivedPoint);
71+ const _web3 = need.web3(web3);
72+ const _contracts = need.contracts(contracts);
73+
74+ try {
75+ await claimPointFromInvite({
76+ inviteWallet: _inviteWallet,
77+ wallet: _wallet,
78+ point: _point,
79+ web3: _web3,
80+ contracts: _contracts,
81+ onUpdate: handleUpdate,
82+ });
83+ // set the global wallet
84+ setUrbitWallet(derivedWallet);
85+ setPointCursor(derivedPoint);
86+ await timeout(3000);
87+ // and redirect to login
88+ goToLogin();
89+ } catch (error) {
90+ // some generic error
91+ setGeneralError(error);
3892 }
39− })();
93+ }, [
94+ inviteWallet,
95+ derivedWallet,
96+ derivedPoint,
97+ web3,
98+ contracts,
99+ setUrbitWallet,
100+ setPointCursor,
101+ handleUpdate,
102+ goToLogin,
103+ ]);
40104
41105 useLifecycle(() => {
42− // on mount, start transactions
106+ claimPoint();
43107 });
44108
45109 return (
46110 <Grid gap={4} className={className}>
47111 <Grid.Item full as={Steps} num={2} total={3} />
48112 <Grid.Item full as={H4}>
49− {titleText}
113+ {label}
50114 </Grid.Item>
51− <Grid.Item full as={LoadingBar} progress={0.5} />
52− <Grid.Item full as={Text} className="green4">
53− This process can take up to 5 minutes to complete. Don't leave this page
54− until the process is complete.
115+ <Grid.Item full as={Grid}>
116+ <Grid.Item full as={LoadingBar} progress={progress} />
117+ <Grid.Item full>
118+ <Text className="f5 green4">
119+ This process can take up to 5 minutes to complete. Don't leave this
120+ page until the process is complete.
121+ </Text>
122+ </Grid.Item>
55123 </Grid.Item>
56124
57− {isClaiming && (
125+ {progress < 0 && (
58126 <Grid.Item full as={WarningBox}>
59127 Never give your Master Ticket to anyone
60128 </Grid.Item>
61129 )}
130+
131+ {needFunds && (
132+ <Grid.Item full>
133+ <Highlighted>
134+ The address {needFunds.address} needs at least{' '}
135+ {fromWei(needFunds.minBalance)} ETH and currently has{' '}
136+ {fromWei(needFunds.balance)} ETH. Waiting until the account has
137+ enough funds.
138+ </Highlighted>
139+ </Grid.Item>
140+ )}
141+
142+ {generalError && (
143+ <Grid.Item full>
144+ <ErrorText>{generalError.message.toString()}</ErrorText>
145+ </Grid.Item>
146+ )}
62147 </Grid>
63148 );
64149}
src/views/Activate/PassportVerify.js+5−7
@@ -1,5 +1,5 @@
11import React, { useCallback, useMemo } from 'react';
2−import { Grid, H4, P, Input } from 'indigo-react';
2+import { Grid, H4, P, Input, Text } from 'indigo-react';
33
44import * as need from 'lib/need';
55import { useLocalRouter } from 'lib/LocalRouter';
@@ -36,12 +36,10 @@ export default function PassportVerify({ className }) {
3636 <Grid.Item full as={H4}>
3737 Verify Passport
3838 </Grid.Item>
39− <Grid.Item full>
40− <P>
41− After you download your passport, verify your custody. Your passport
42− should be a folder of image files. One of them is your Master Ticket.
43− Open it and enter the 4 word phrase below (with hyphens).
44− </P>
39+ <Grid.Item full as={Text} className="f5">
40+ After you download your passport, verify your custody. Your passport
41+ should be a folder of image files. One of them is your Master Ticket.
42+ Open it and enter the 4 word phrase below (with hyphens).
4543 </Grid.Item>
4644 <Grid.Item full as={Input} {...ticketInput} />
4745 <Grid.Item
src/views/InviteTicket.js+2−2
@@ -28,7 +28,7 @@ import {
2828 WALLET_STATES,
2929 TRANSACTION_STATES,
3030} from '../lib/invite';
31−import { generateWallet, startTransactions } from '../lib/invite';
31+import { generateWallet, claimPointFromInvite } from '../lib/invite';
3232import { withNetwork } from '../store/network';
3333import { withWallet } from '../store/wallet';
3434import { Grid } from 'indigo-react';
@@ -303,7 +303,7 @@ class InviteTicket extends React.Component {
303303 ),
304304 });
305305
306− startTransactions({
306+ claimPointFromInvite({
307307 inviteWalletM: inviteWallet,
308308 realWalletM: realWallet,
309309 realPointM: realPoint,
src/views/Login/Keystore.js+2
@@ -14,8 +14,10 @@ import { useWallet } from 'store/wallet';
1414import * as need from 'lib/need';
1515import { EthereumWallet, WALLET_TYPES } from 'lib/wallet';
1616import useWalletType from 'lib/useWalletType';
17+import useResetPointCursor from 'lib/useResetPointCursor';
1718
1819export default function Keystore({ loginCompleted }) {
20+ useResetPointCursor();
1921 useWalletType(WALLET_TYPES.KEYSTORE);
2022
2123 // globals
src/views/Login/Ledger.js+2
@@ -16,6 +16,7 @@ import { useWallet } from 'store/wallet';
1616import { LEDGER_LIVE_PATH, LEDGER_LEGACY_PATH } from 'lib/ledger';
1717import useWalletType from 'lib/useWalletType';
1818import { WALLET_TYPES } from 'lib/wallet';
19+import useResetPointCursor from 'lib/useResetPointCursor';
1920
2021const pathOptions = [
2122 { title: 'Ledger Live', value: LEDGER_LIVE_PATH },
@@ -28,6 +29,7 @@ const chopHdPrefix = str => (str.slice(0, 2) === 'm/' ? str.slice(2) : str);
2829const addHdPrefix = str => (str.slice(0, 2) === 'm/' ? str : 'm/' + str);
2930
3031export default function Ledger({ loginCompleted }) {
32+ useResetPointCursor();
3133 useWalletType(WALLET_TYPES.LEDGER);
3234
3335 const { wallet, setWallet, setWalletHdPath } = useWallet();
src/views/Login/Mnemonic.js+3
@@ -14,9 +14,12 @@ import { useWallet } from 'store/wallet';
1414
1515import { walletFromMnemonic, WALLET_TYPES } from 'lib/wallet';
1616import useWalletType from 'lib/useWalletType';
17+import useResetPointCursor from 'lib/useResetPointCursor';
1718
1819export default function Mnemonic({ advanced, loginCompleted }) {
20+ useResetPointCursor();
1921 useWalletType(WALLET_TYPES.MNEMONIC);
22+
2023 const {
2124 wallet,
2225 setWallet,
src/views/Login/PrivateKey.js+2
@@ -10,8 +10,10 @@ import { useWallet } from 'store/wallet';
1010
1111import { EthereumWallet, WALLET_TYPES } from 'lib/wallet';
1212import useWalletType from 'lib/useWalletType';
13+import useResetPointCursor from 'lib/useResetPointCursor';
1314
1415export default function PrivateKey({ loginCompleted }) {
16+ useResetPointCursor();
1517 useWalletType(WALLET_TYPES.PRIVATE_KEY);
1618 const { wallet, setWallet } = useWallet();
1719
src/views/Login/Shards.js+2
@@ -15,8 +15,10 @@ import { useWallet } from 'store/wallet';
1515
1616import { urbitWalletFromTicket, WALLET_TYPES } from 'lib/wallet';
1717import useWalletType from 'lib/useWalletType';
18+import useResetPointCursor from 'lib/useResetPointCursor';
1819
1920export default function Shards({ loginCompleted }) {
21+ useResetPointCursor();
2022 useWalletType(WALLET_TYPES.SHARDS);
2123
2224 const { wallet, setUrbitWallet } = useWallet();
src/views/Login/Ticket.js+2
@@ -19,6 +19,7 @@ import { usePointCursor } from 'store/pointCursor';
1919import * as need from 'lib/need';
2020import { WALLET_TYPES, urbitWalletFromTicket } from 'lib/wallet';
2121import useWalletType from 'lib/useWalletType';
22+import useResetPointCursor from 'lib/useResetPointCursor';
2223
2324//TODO should be part of InputWithStatus component
2425const INPUT_STATUS = {
@@ -28,6 +29,7 @@ const INPUT_STATUS = {
2829};
2930
3031export default function Ticket({ advanced, loginCompleted }) {
32+ useResetPointCursor();
3133 useWalletType(WALLET_TYPES.TICKET);
3234 // globals
3335 const { contracts } = useNetwork();
src/views/Login/Trezor.js+2
@@ -13,6 +13,7 @@ import { InnerLabelDropdown } from 'components/old/Base';
1313import { TREZOR_PATH } from 'lib/trezor';
1414import useWalletType from 'lib/useWalletType';
1515import { WALLET_TYPES } from 'lib/wallet';
16+import useResetPointCursor from 'lib/useResetPointCursor';
1617
1718import { useWallet } from 'store/wallet';
1819
@@ -22,6 +23,7 @@ const accountOptions = [
2223];
2324
2425export default function Trezor({ loginCompleted }) {
26+ useResetPointCursor();
2527 useWalletType(WALLET_TYPES.TREZOR);
2628
2729 const { wallet, setWallet, setWalletHdPath } = useWallet();