on master help sign in
dx: more Typescript cleanup
64ad57dtomholford
src/components/Highlighted.js+1−1
@@ -3,7 +3,7 @@ import cn from 'classnames';
3
3
4export default function Highlighted({
4export default function Highlighted({
5 as: As = 'span',
5 as: As = 'span',
6− className,
6+ className = '',
7 warning = false,
7 warning = false,
8 ...rest
8 ...rest
9}) {
9}) {
src/components/View.tsx+1−2
@@ -30,13 +30,12 @@ function View({
30 full = false,
30 full = false,
31 hideBack = false,
31 hideBack = false,
32 pop = noop,
32 pop = noop,
33− header,
33+ header = React.Fragment,
34 id,
34 id,
35 centered = false,
35 centered = false,
36 ...rest
36 ...rest
37}: ViewProps) {
37}: ViewProps) {
38 const { reset }: any = useHistory();
38 const { reset }: any = useHistory();
39− // @ts-ignore
40 const isMobile: boolean = useBreakpoints([true, false, false]);
39 const isMobile: boolean = useBreakpoints([true, false, false]);
41 const shouldInset = inset && !isMobile;
40 const shouldInset = inset && !isMobile;
42
41
src/components/copiable/CopiableAddressWrap.js+1−1
@@ -3,7 +3,7 @@ import cn from 'classnames';
3
3
4import CopiableWithTooltip from './CopiableWithTooltip';
4import CopiableWithTooltip from './CopiableWithTooltip';
5
5
6−export default function CopiableAddressWrap({ className, ...rest }) {
6+export default function CopiableAddressWrap({ className = '', ...rest }) {
7 return (
7 return (
8 <CopiableWithTooltip className={cn(className, 'mono', 'wrap')} {...rest} />
8 <CopiableWithTooltip className={cn(className, 'mono', 'wrap')} {...rest} />
9 );
9 );
src/lib/flowCommand.ts+31−3
@@ -21,14 +21,42 @@ const COMMANDS = {
21 XPUB: 'xpub',
21 XPUB: 'xpub',
22};
22};
23
23
24+interface LockupFlowKind {
25+ kind: 'takeLockup';
26+ lock: 'linear' | 'conditional';
27+ from: string;
28+ [k: string]: string | boolean;
29+}
30+
31+interface BitcoinFlowKind {
32+ kind: 'btc';
33+ utx: string;
34+ [k: string]: string | boolean;
35+}
36+
37+interface XpubFlowKind {
38+ kind: 'xpub';
39+ [k: string]: string | boolean;
40+}
41+
42+interface DefaultFlowKind {
43+ kind?: string;
44+ [k: string]: string | boolean | undefined;
45+}
46+
24−export type FlowType = { [k: string]: string | boolean } | null;
47+export type FlowType =
48+ | LockupFlowKind
49+ | BitcoinFlowKind
50+ | XpubFlowKind
51+ | DefaultFlowKind
52+ | null;
25
53
26const useFlowCommand = () => {
54const useFlowCommand = () => {
27 const flow = useMemo(() => {
55 const flow = useMemo(() => {
28 let flow: FlowType = {};
56 let flow: FlowType = {};
29
57
30 window.location.search
58 window.location.search
31− .substr(1)
59+ .substring(1)
32 .split('&')
60 .split('&')
33 .forEach(arg => {
61 .forEach(arg => {
34 if ('' === arg) return;
62 if ('' === arg) return;
@@ -38,7 +66,7 @@ const useFlowCommand = () => {
38 }
66 }
39 });
67 });
40
68
41− if (typeof flow === 'object') {
69+ if (flow && typeof flow === 'object') {
42 switch (flow.kind) {
70 switch (flow.kind) {
43 case COMMANDS.TAKE_LOCKUP:
71 case COMMANDS.TAKE_LOCKUP:
44 flow.lock = flow.lock || 'linear';
72 flow.lock = flow.lock || 'linear';
src/lib/types/ValueOf.tsnew file+1
@@ -0,0 +1 @@
1+export type ValueOf<T> = T[keyof T];
src/views/Bitcoin/Bitcoin.tsx+25−15
@@ -6,12 +6,12 @@ import { useWallet } from 'store/wallet';
6
6
7import * as bitcoin from 'bitcoinjs-lib';
7import * as bitcoin from 'bitcoinjs-lib';
8import { useLocalRouter } from 'lib/LocalRouter';
8import { useLocalRouter } from 'lib/LocalRouter';
9−import { COMMANDS, useFlowCommand } from 'lib/flowCommand';
9+import { COMMANDS, FlowType, useFlowCommand } from 'lib/flowCommand';
10import * as need from 'lib/need';
10import * as need from 'lib/need';
11import useCopiable from 'lib/useCopiable';
11import useCopiable from 'lib/useCopiable';
12
12
13import View from 'components/View';
13import View from 'components/View';
14−import L2BackHeader from 'components/L2/Headers/L2BackHeader';
14+import L2BackHeader from 'components/L2/Headers/L2BackHeader';
15import Window from 'components/L2/Window/Window';
15import Window from 'components/L2/Window/Window';
16import HeaderPane from 'components/L2/Window/HeaderPane';
16import HeaderPane from 'components/L2/Window/HeaderPane';
17import BodyPane from 'components/L2/Window/BodyPane';
17import BodyPane from 'components/L2/Window/BodyPane';
@@ -52,10 +52,12 @@ const BITCOIN_TESTNET_INFO = {
52export default function Bitcoin() {
52export default function Bitcoin() {
53 const { pop }: any = useLocalRouter();
53 const { pop }: any = useLocalRouter();
54 const { urbitWallet }: any = useWallet();
54 const { urbitWallet }: any = useWallet();
55− const flow = useFlowCommand();
55+ const flow: FlowType = useFlowCommand();
56
56
57 const [signedTx, setSignedTx] = useState('');
57 const [signedTx, setSignedTx] = useState('');
58− const [psbt, setPsbt] = useState({});
58+ const [psbt, setPsbt] = useState<ReturnType<
59+ typeof bitcoin.Psbt.fromBase64
60+ > | null>(null);
59
61
60 // set to false for BTC testnet
62 // set to false for BTC testnet
61 const isMainnet = true;
63 const isMainnet = true;
@@ -77,13 +79,14 @@ export default function Bitcoin() {
77
79
78 const [doCopy, didCopy] = useCopiable(xpub);
80 const [doCopy, didCopy] = useCopiable(xpub);
79
81
80− const onSubmit = (values: any) => {
82+ const onSubmit = (values: { unsignedTransaction: string }) => {
81 const newPsbt = bitcoin.Psbt.fromBase64(values.unsignedTransaction);
83 const newPsbt = bitcoin.Psbt.fromBase64(values.unsignedTransaction);
82−
83− const isTestnet = newPsbt.data.inputs[0].bip32Derivation[0].path.startsWith(
84+ const derivations = newPsbt.data.inputs[0]?.bip32Derivation;
84− "m/84'/1'/0'/"
85+ const firstDerivation =
85− );
86+ derivations && derivations.length > 0 ? derivations[0] : null;
86−
87+ const firstDerivationPath = firstDerivation ? firstDerivation.path : null;
88+ const isTestnet =
89+ firstDerivationPath && firstDerivationPath.startsWith("m/84'/1'/0'/");
87 const derivationPrefix = isTestnet ? "m/84'/1'/0'/" : "m/84'/0'/0'/";
90 const derivationPrefix = isTestnet ? "m/84'/1'/0'/" : "m/84'/0'/0'/";
88
91
89 const btcWallet = isTestnet
92 const btcWallet = isTestnet
@@ -91,13 +94,17 @@ export default function Bitcoin() {
91 : bitcoin.bip32.fromBase58(zprv, BITCOIN_MAINNET_INFO);
94 : bitcoin.bip32.fromBase58(zprv, BITCOIN_MAINNET_INFO);
92
95
93 try {
96 try {
97+ if (!firstDerivationPath) {
98+ throw new Error('No derivation path available');
99+ }
94 const hex = newPsbt.data.inputs
100 const hex = newPsbt.data.inputs
95 .reduce((psbt, input, idx) => {
101 .reduce((psbt, input, idx) => {
96 // removing already derived part, eg m/84'/0'/0'/0/0 becomes 0/0
102 // removing already derived part, eg m/84'/0'/0'/0/0 becomes 0/0
97− const path = input.bip32Derivation[0].path
98− .split(derivationPrefix)
103+ const path = firstDerivationPath.split(derivationPrefix).join('');
99− .join('');
100 const prv = btcWallet.derivePath(path).privateKey;
104 const prv = btcWallet.derivePath(path).privateKey;
105+ if (!prv) {
106+ throw new Error('Private key unavailable');
107+ }
101 return psbt.signInput(idx, bitcoin.ECPair.fromPrivateKey(prv));
108 return psbt.signInput(idx, bitcoin.ECPair.fromPrivateKey(prv));
102 }, newPsbt)
109 }, newPsbt)
103 .finalizeAllInputs()
110 .finalizeAllInputs()
@@ -112,9 +119,11 @@ export default function Bitcoin() {
112 }
119 }
113 };
120 };
114
121
115− const initialValues = {};
122+ let initialValues = {
123+ unsignedTransaction: '',
124+ };
116 if (flow && COMMANDS.BITCOIN === flow.kind) {
125 if (flow && COMMANDS.BITCOIN === flow.kind) {
117− initialValues.unsignedTransaction = flow.utx;
126+ initialValues.unsignedTransaction = flow.utx as string;
118 }
127 }
119
128
120 return (
129 return (
@@ -177,6 +186,7 @@ export default function Bitcoin() {
177 </Grid.Item>
186 </Grid.Item>
178 )}
187 )}
179 {signedTx &&
188 {signedTx &&
189+ psbt &&
180 psbt.txOutputs.map(e => (
190 psbt.txOutputs.map(e => (
181 <Grid.Item full className="mt4" key={e.address}>
191 <Grid.Item full className="mt4" key={e.address}>
182 <span>{e.address}</span>
192 <span>{e.address}</span>
src/views/Invite/Cohort.tsx+4
@@ -512,6 +512,8 @@ export default function InviteCohort() {
512 {loading && <Box>{generatingCodesText}</Box>}
512 {loading && <Box>{generatingCodesText}</Box>}
513 </Box>
513 </Box>
514 <Row className="download-buttons">
514 <Row className="download-buttons">
515+ {/*
516+ // @ts-ignore */}
515 <Button
517 <Button
516 center
518 center
517 className="ph4 close-button"
519 className="ph4 close-button"
@@ -519,6 +521,8 @@ export default function InviteCohort() {
519 onClick={() => setShowCsvModal(false)}>
521 onClick={() => setShowCsvModal(false)}>
520 Close
522 Close
521 </Button>
523 </Button>
524+ {/*
525+ // @ts-ignore */}
522 <Button
526 <Button
523 center
527 center
524 className="ph4 download-button"
528 className="ph4 download-button"
src/views/Login.tsx+1−1
@@ -64,7 +64,7 @@ export default function Login() {
64 };
64 };
65
65
66 return (
66 return (
67− <View inset>
67+ <View inset hideBack={true}>
68 <Grid>
68 <Grid>
69 <Grid.Item
69 <Grid.Item
70 full
70 full