on master help sign in
checkpoint: implementing disclaimer, passport screens
1c0703eMatt Condon (shrugs)
src/components/Blinky.js+4−3
@@ -9,20 +9,21 @@ const BLINK_AFTER_MS = 2500; // ms
9
9
10export const matchBlinky = obj =>
10export const matchBlinky = obj =>
11 obj.matchWith({
11 obj.matchWith({
12− Nothing: () => <Blinky />,
12+ Nothing: () => <Blinky delayed />,
13 Just: p => p.value,
13 Just: p => p.value,
14 });
14 });
15
15
16export default function Blinky({
16export default function Blinky({
17 a = kLoadingCharacter,
17 a = kLoadingCharacter,
18 b = kInterstitialCharacter,
18 b = kInterstitialCharacter,
19+ delayed = false,
19}) {
20}) {
20 const [value, setValue] = useState(true);
21 const [value, setValue] = useState(true);
21 const now = useRef(new Date());
22 const now = useRef(new Date());
22
23
23 useInterval(() => {
24 useInterval(() => {
24− // only start blinking if we've elapsed enough time
25+ // only start blinking if we've elapsed enough time and want to delay
25− if (new Date() - now.current > BLINK_AFTER_MS) {
26+ if (!delayed || new Date() - now.current > BLINK_AFTER_MS) {
26 setValue(val => !val);
27 setValue(val => !val);
27 }
28 }
28 }, 1000);
29 }, 1000);
src/components/Buttons.js+9
@@ -4,3 +4,12 @@ import { Button } from 'indigo-react';
4// TODO: use svg icons
4// TODO: use svg icons
5export const ForwardButton = props => <Button accessory="→" {...props} />;
5export const ForwardButton = props => <Button accessory="→" {...props} />;
6export const DownloadButton = props => <Button accessory="⬇" {...props} />;
6export const DownloadButton = props => <Button accessory="⬇" {...props} />;
7+export const OutButton = props => (
8+ <Button as="a" target="_blank" accessory="↗" {...props} />
9+);
10+
11+export const OfflineButton = props => (
12+ <OutButton {...props} href="https://github.com/urbit/bridge/releases">
13+ Offline
14+ </OutButton>
15+);
src/components/FooterButton.js+2−2
@@ -3,13 +3,13 @@ import { Grid, Button } from 'indigo-react';
3
3
4import Footer from './Footer';
4import Footer from './Footer';
5
5
6−export default function FooterButton(props) {
6+export default function FooterButton({ as: As = Button, ...props }) {
7 return (
7 return (
8 <Footer>
8 <Footer>
9 <Grid className="pt2">
9 <Grid className="pt2">
10 <Grid.Divider />
10 <Grid.Divider />
11 <Grid.Item full>
11 <Grid.Item full>
12− <Button {...props} />
12+ <As {...props} />
13 </Grid.Item>
13 </Grid.Item>
14 </Grid>
14 </Grid>
15 </Footer>
15 </Footer>
src/components/Inputs.js+11
@@ -141,6 +141,17 @@ export function usePointInput({ initialValue = '~', ...rest }) {
141 };
141 };
142}
142}
143
143
144+export function useCheckboxInput({ initialValue, ...rest }) {
145+ return firstOf(
146+ useForm([
147+ {
148+ type: 'checkbox',
149+ ...rest,
150+ },
151+ ])
152+ );
153+}
154+
144const kEmailValidators = [validateEmail, validateNotEmpty];
155const kEmailValidators = [validateEmail, validateNotEmpty];
145export const buildEmailInputConfig = extra => ({
156export const buildEmailInputConfig = extra => ({
146 type: 'email',
157 type: 'email',
src/components/Passport.js+57−6
@@ -2,7 +2,7 @@ import React from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3import Maybe from 'folktale/maybe';
3import Maybe from 'folktale/maybe';
4import * as ob from 'urbit-ob';
4import * as ob from 'urbit-ob';
5−import { Grid, Flex } from 'indigo-react';
5+import { Grid, Flex, Text } from 'indigo-react';
6import { times } from 'lodash';
6import { times } from 'lodash';
7
7
8import usePointBirthday from 'lib/usePointBirthday';
8import usePointBirthday from 'lib/usePointBirthday';
@@ -16,13 +16,33 @@ const buildDate = char =>
16const kDateA = buildDate(kLoadingCharacter);
16const kDateA = buildDate(kLoadingCharacter);
17const kDateB = buildDate(kInterstitialCharacter);
17const kDateB = buildDate(kInterstitialCharacter);
18
18
19+const kTicketCharacterLength = 40;
20+const kPendingTicket = times(
21+ kTicketCharacterLength,
22+ () => kLoadingCharacter
23+).join('');
24+const kValidTicket =
25+ times(kTicketCharacterLength, () => kLoadingCharacter).join('') + '◆';
26+
27+const kVisibleAddressCharacters = 20;
28+const kEmptyHalfAddress = times(kVisibleAddressCharacters, () => '<').join('');
29+const bufferAddressCharacters = times(40, () => '<').join('');
30+
19/**
31/**
20 * point is Maybe<number>
32 * point is Maybe<number>
33+ * ticket is boolean
34+ * address is null | Maybe<string>
21 */
35 */
22−export default function Passport({ point, className }) {
36+export default function Passport({
37+ point,
38+ className,
39+ ticket = null,
40+ address = null,
41+ mini = false,
42+}) {
23 const birthday = usePointBirthday(point.getOrElse(null));
43 const birthday = usePointBirthday(point.getOrElse(null));
24 const visualBirthday = birthday.matchWith({
44 const visualBirthday = birthday.matchWith({
25− Nothing: () => <Blinky a={kDateA} b={kDateB} />,
45+ Nothing: () => <Blinky a={kDateA} b={kDateB} delayed />,
26 Just: p => formatDots(p.value),
46 Just: p => formatDots(p.value),
27 });
47 });
28
48
@@ -35,18 +55,49 @@ export default function Passport({ point, className }) {
35 Just: p => p.value,
55 Just: p => p.value,
36 });
56 });
37
57
58+ const showTicket = ticket !== null;
59+ const showValidTicket = !!ticket;
60+ const visibleTicket = showValidTicket ? kValidTicket : kPendingTicket;
61+ const visibleAddress =
62+ address &&
63+ `${address.matchWith({
64+ Nothing: () => kEmptyHalfAddress,
65+ Just: p => p.value.slice(0, kVisibleAddressCharacters),
66+ })}${bufferAddressCharacters}`;
67+
38 return (
68 return (
39− <Grid gap={16} className={cn('bg-black r8 p7', className)}>
69+ <Grid gap={4} className={cn('bg-black r8 p7', className)}>
40 <Grid.Item cols={[1, 4]} className="bg-green">
70 <Grid.Item cols={[1, 4]} className="bg-green">
41 <MaybeSigil patp={name} size={64} margin={0} />
71 <MaybeSigil patp={name} size={64} margin={0} />
42 </Grid.Item>
72 </Grid.Item>
43 <Grid.Item as={Flex} cols={[4, 13]} col justify="between">
73 <Grid.Item as={Flex} cols={[4, 13]} col justify="between">
44 <Flex.Item className="mono white f5">{visualName}</Flex.Item>
74 <Flex.Item className="mono white f5">{visualName}</Flex.Item>
45 <Flex.Item as={Flex} col>
75 <Flex.Item as={Flex} col>
46− <Flex.Item className="mono gray4 f6 uppercase">Birth Time</Flex.Item>
76+ <Flex.Item as={Text} className="mono gray4 uppercase">
77+ Birth Time
78+ </Flex.Item>
47− <Flex.Item className="mono gray4 f6">{visualBirthday}</Flex.Item>
79+ <Flex.Item as={Text} className="mono gray4">
80+ {visualBirthday}
81+ </Flex.Item>
48 </Flex.Item>
82 </Flex.Item>
49 </Grid.Item>
83 </Grid.Item>
84+ {!mini && showTicket && (
85+ <Grid.Item full className="mv3" as={Flex} col>
86+ <Flex.Item as={Text} className="mono gray4 uppercase">
87+ Master Ticket
88+ </Flex.Item>
89+ <Flex.Item
90+ as={Text}
91+ className={cn('mono gray4', {
92+ green3: showValidTicket,
93+ })}>
94+ {visibleTicket}
95+ </Flex.Item>
96+ <Flex.Item as={Text} className="mono gray4">
97+ {visibleAddress}
98+ </Flex.Item>
99+ </Grid.Item>
100+ )}
50 </Grid>
101 </Grid>
51 );
102 );
52}
103}
src/indigo-react/components/AccessoryIcon.js+1−1
@@ -3,7 +3,7 @@ import React from 'react';
3import Flex from './Flex';
3import Flex from './Flex';
4
4
5const PENDING_ACCESSORY = '⋯';
5const PENDING_ACCESSORY = '⋯';
6−const SUCCESS_ACCESSORY = '✔';
6+const SUCCESS_ACCESSORY = '✓';
7const FAILURE_ACCESSORY = '×';
7const FAILURE_ACCESSORY = '×';
8
8
9function AccessoryIcon({ ...props }) {
9function AccessoryIcon({ ...props }) {
src/indigo-react/components/Button.js+1−1
@@ -24,7 +24,7 @@ export default function Button({
24 return (
24 return (
25 <Grid
25 <Grid
26 as="a"
26 as="a"
27− gap={4}
27+ gap={1}
28 className={cn(
28 className={cn(
29 'pointer pv4 truncate flex-row justify-between',
29 'pointer pv4 truncate flex-row justify-between',
30 {
30 {
src/indigo-react/components/CheckboxInput.jsnew file+82
@@ -0,0 +1,82 @@
1+import React from 'react';
2+import cn from 'classnames';
3+
4+import Flex from './Flex';
5+
6+// TODO: make this look like screens
7+export default function CheckboxInput({
8+ // visuals
9+ name,
10+ label,
11+ className,
12+
13+ // callbacks
14+ onValue,
15+ onPass,
16+ onError,
17+ onFocus,
18+ onEnter,
19+
20+ // state from hook
21+ focused,
22+ pass,
23+ visiblyPassed,
24+ error,
25+ data,
26+ bind,
27+ autoFocus,
28+ disabled,
29+
30+ // ignored
31+ initialValue,
32+ validators,
33+ transformers,
34+
35+ // extra
36+ ...rest
37+}) {
38+ return (
39+ <Flex
40+ className={className}
41+ row
42+ align="center"
43+ style={{
44+ ...(disabled && {
45+ pointerEvents: 'none',
46+ cursor: 'not-allowed',
47+ }),
48+ }}>
49+ <Flex.Item
50+ as="input"
51+ {...rest}
52+ className={cn(
53+ 'b b1 p3 outline-none',
54+ {
55+ 'bg-white': !disabled,
56+ 'bg-gray1': disabled,
57+ },
58+ {
59+ gray4: !focused,
60+ black: focused,
61+ },
62+ {
63+ 'b-green3': visiblyPassed,
64+ 'b-black': focused && !visiblyPassed,
65+ 'b-yellow3': !focused && error,
66+ 'b-gray3': !focused && !error && !visiblyPassed,
67+ }
68+ )}
69+ id={name}
70+ name={name}
71+ {...bind}
72+ />
73+ <Flex.Item
74+ as="label"
75+ className="f6 ph3 lh-tall us-none"
76+ htmlFor={name}
77+ flex>
78+ {label}
79+ </Flex.Item>
80+ </Flex>
81+ );
82+}
src/indigo-react/components/Grid.js+7−2
@@ -44,14 +44,19 @@ Grid.Item = function GridItem({
44 );
44 );
45};
45};
46
46
47−Grid.Divider = function GridDivider({ vertical = false, className, ...rest }) {
47+Grid.Divider = function GridDivider({
48+ vertical = false,
49+ color = 'gray2',
50+ className,
51+ ...rest
52+}) {
48 return (
53 return (
49 <div
54 <div
50 style={{
55 style={{
51 height: vertical ? 'auto' : '1px',
56 height: vertical ? 'auto' : '1px',
52 width: vertical ? '1px' : 'auto',
57 width: vertical ? '1px' : 'auto',
53 }}
58 }}
54− className={cn('full', className || 'bg-gray2')}
59+ className={cn('full', `bg-${color}`, className)}
55 {...rest}
60 {...rest}
56 />
61 />
57 );
62 );
src/indigo-react/components/Input.js+10−10
@@ -68,9 +68,16 @@ export default function Input({
68 onFocus && onFocus(focused);
68 onFocus && onFocus(focused);
69 }, [focused]); // eslint-disable-line react-hooks/exhaustive-deps
69 }, [focused]); // eslint-disable-line react-hooks/exhaustive-deps
70
70
71− console.log(name, visiblyPassed, error);
72 return (
71 return (
72+ <Flex
73− <Flex className={className} col>
73+ className={className}
74+ col
75+ style={{
76+ ...(disabled && {
77+ pointerEvents: 'none',
78+ cursor: 'not-allowed',
79+ }),
80+ }}>
74 <Flex.Item as="label" className="f6 lh-tall" htmlFor={name}>
81 <Flex.Item as="label" className="f6 lh-tall" htmlFor={name}>
75 {label}
82 {label}
76 </Flex.Item>
83 </Flex.Item>
@@ -78,9 +85,8 @@ export default function Input({
78 <Flex.Item
85 <Flex.Item
79 as="input"
86 as="input"
80 {...rest}
87 {...rest}
81− cols={[1, accessory ? 11 : 13]}
82 className={cn(
88 className={cn(
83− 'rel b b1 p3 outline-none',
89+ 'b b1 p3 outline-none',
84 { mono },
90 { mono },
85 {
91 {
86 'bg-white': !disabled,
92 'bg-white': !disabled,
@@ -98,12 +104,6 @@ export default function Input({
98 }
104 }
99 // TODO: inputClassName ?
105 // TODO: inputClassName ?
100 )}
106 )}
101− style={{
102− ...(disabled && {
103− pointerEvents: 'none',
104− cursor: 'not-allowed',
105− }),
106− }}
107 id={name}
107 id={name}
108 name={name}
108 name={name}
109 onKeyPress={onKeyPress}
109 onKeyPress={onKeyPress}
src/indigo-react/components/Typography.js+1
@@ -14,6 +14,7 @@ export const H5 = typeWith('h5');
14export const H6 = typeWith('h6');
14export const H6 = typeWith('h6');
15export const Caption = typeWith('caption');
15export const Caption = typeWith('caption');
16export const P = typeWith('p');
16export const P = typeWith('p');
17+export const B = typeWith('b');
17
18
18export const Breadcrumb = typeWith('span', 'f6');
19export const Breadcrumb = typeWith('span', 'f6');
19export const Text = typeWith('span', 'f5');
20export const Text = typeWith('span', 'f5');
src/indigo-react/index.js+1
@@ -2,6 +2,7 @@ export { default as IndigoApp } from './components/IndigoApp';
2export { default as Grid } from './components/Grid';
2export { default as Grid } from './components/Grid';
3export { default as Flex } from './components/Flex';
3export { default as Flex } from './components/Flex';
4export { default as Input } from './components/Input';
4export { default as Input } from './components/Input';
5+export { default as CheckboxInput } from './components/CheckboxInput';
5export { default as AccessoryIcon } from './components/AccessoryIcon';
6export { default as AccessoryIcon } from './components/AccessoryIcon';
6export { default as Button } from './components/Button';
7export { default as Button } from './components/Button';
7export { default as IconButton } from './components/IconButton';
8export { default as IconButton } from './components/IconButton';
src/indigo-react/indigo.css+27−12
@@ -13,7 +13,7 @@
13 * git+https://github.com/urbit/Indigo.git
13 * git+https://github.com/urbit/Indigo.git
14 * Bugs: https://github.com/urbit/Indigo/issues
14 * Bugs: https://github.com/urbit/Indigo/issues
15 * License: MIT
15 * License: MIT
16− * Timestamp: Mon Jun 24 2019 19:57:25 GMT-0700 (Pacific Daylight Time)
16+ * Timestamp: Thu Jun 27 2019 14:14:25 GMT-0700 (Pacific Daylight Time)
17 *******************************************************************************/
17 *******************************************************************************/
18/**********************
18/**********************
19Color variables
19Color variables
@@ -2032,30 +2032,45 @@ caption,
2032 .fourth-4-lg {
2032 .fourth-4-lg {
2033 grid-area: auto / 10 / auto / 13; } }
2033 grid-area: auto / 10 / auto / 13; } }
2034
2034
2035−.gap1 {
2035+.gap0 {
2036− gap: 1px; }
2037−
2038−.gap2 {
2039− gap: 2px; }
2036+ gap: 0px; }
2040
2037
2041−.gap4 {
2038+.gap1 {
2042 gap: 4px; }
2039 gap: 4px; }
2043
2040
2044−.gap8 {
2041+.gap2 {
2045 gap: 8px; }
2042 gap: 8px; }
2046
2043
2047−.gap12 {
2044+.gap3 {
2048 gap: 12px; }
2045 gap: 12px; }
2049
2046
2050−.gap16 {
2047+.gap4 {
2051 gap: 16px; }
2048 gap: 16px; }
2052
2049
2053−.gap24 {
2050+.gap5 {
2051+ gap: 20px; }
2052+
2053+.gap6 {
2054 gap: 24px; }
2054 gap: 24px; }
2055
2055
2056−.gap32 {
2056+.gap7 {
2057 gap: 32px; }
2057 gap: 32px; }
2058
2058
2059+.gap8 {
2060+ gap: 48px; }
2061+
2062+.gap9 {
2063+ gap: 64px; }
2064+
2065+.gap10 {
2066+ gap: 96px; }
2067+
2068+.gap11 {
2069+ gap: 160px; }
2070+
2071+.gap12 {
2072+ gap: 288px; }
2073+
2059.c1-2 {
2074.c1-2 {
2060 grid-column-start: 1;
2075 grid-column-start: 1;
2061 grid-column-end: 2; }
2076 grid-column-end: 2; }
src/indigo-react/lib/useForm.js+14−2
@@ -70,10 +70,21 @@ export default function useForm(configs = []) {
70 [byName]
70 [byName]
71 );
71 );
72
72
73+ const getValue = useCallback(
74+ (name, e) => {
75+ if (byName[name].type === 'checkbox') {
76+ return e.target.checked;
77+ }
78+
79+ return e.target.value;
80+ },
81+ [byName]
82+ );
83+
73 // on change, transform and set value
84 // on change, transform and set value
74 const onChange = useCallback(
85 const onChange = useCallback(
75− name => e => setValue(name, transform(name, e.target.value)), //
86+ name => e => setValue(name, transform(name, getValue(name, e))), //
76− [setValue, transform]
87+ [setValue, transform, getValue]
77 );
88 );
78
89
79 // on focus, update focus
90 // on focus, update focus
@@ -155,6 +166,7 @@ export default function useForm(configs = []) {
155 // dom properties below:
166 // dom properties below:
156 bind: {
167 bind: {
157 value: values[name] || initialValue,
168 value: values[name] || initialValue,
169+ checked: !!values[name],
158 onChange: onChange(name),
170 onChange: onChange(name),
159 onFocus: onFocus(name),
171 onFocus: onFocus(name),
160 onBlur: onBlur(name),
172 onBlur: onBlur(name),
src/lib/constants.js+3
@@ -5,6 +5,8 @@ const MAX_STAR = 65535;
5const MIN_PLANET = 65536;
5const MIN_PLANET = 65536;
6const MAX_PLANET = 4294967297;
6const MAX_PLANET = 4294967297;
7
7
8+const ZOD = MIN_GALAXY;
9+
8const PLANET_ENTROPY_BITS = 64;
10const PLANET_ENTROPY_BITS = 64;
9const STAR_ENTROPY_BITS = 128;
11const STAR_ENTROPY_BITS = 128;
10const GALAXY_ENTROPY_BITS = 384;
12const GALAXY_ENTROPY_BITS = 384;
@@ -56,4 +58,5 @@ export {
56 STAR_ENTROPY_BITS,
58 STAR_ENTROPY_BITS,
57 GALAXY_ENTROPY_BITS,
59 GALAXY_ENTROPY_BITS,
58 SEED_ENTROPY_BITS,
60 SEED_ENTROPY_BITS,
61+ ZOD,
59};
62};
src/lib/keys.js+1−1
@@ -73,7 +73,7 @@ const attemptNetworkSeedDerivation = async (next, args) => {
73 //
73 //
74 // following code is intentionally verbose for sake of clarity
74 // following code is intentionally verbose for sake of clarity
75
75
76− const point = need.pointCursor(args.pointCursor);
76+ const point = need.point(args.pointCursor);
77 const pointDetails = need.fromPointCache(args.pointCache, point);
77 const pointDetails = need.fromPointCache(args.pointCache, point);
78
78
79 const revision =
79 const revision =
src/lib/need.js+27−12
@@ -3,34 +3,49 @@
3
3
4import { BRIDGE_ERROR } from './error';
4import { BRIDGE_ERROR } from './error';
5
5
6−const needBuilder = error => obj => {
6+const needBuilder = fn => obj => {
7 if (!obj) {
7 if (!obj) {
8− throw error;
8+ fn();
9 }
9 }
10
10
11 return obj.matchWith({
11 return obj.matchWith({
12− Nothing: () => {
12+ Nothing: fn,
13− throw error;
14− },
15 Just: p => p.value,
13 Just: p => p.value,
16 });
14 });
17};
15};
18
16
19−export const web3 = needBuilder(BRIDGE_ERROR.MISSING_WEB3);
17+export const web3 = needBuilder(() => {
18+ throw new Error(BRIDGE_ERROR.MISSING_WEB3.message);
19+});
20+
20−export const contracts = needBuilder(BRIDGE_ERROR.MISSING_CONTRACTS);
21+export const contracts = needBuilder(() => {
22+ throw new Error(BRIDGE_ERROR.MISSING_CONTRACTS.message);
23+});
24+
21−export const wallet = needBuilder(BRIDGE_ERROR.MISSING_WALLET);
25+export const wallet = needBuilder(() => {
26+ throw new Error(BRIDGE_ERROR.MISSING_WALLET.message);
27+});
28+
22export const addressFromWallet = obj => wallet(obj).address;
29export const addressFromWallet = obj => wallet(obj).address;
30+
23−export const pointCursor = needBuilder(BRIDGE_ERROR.MISSING_POINT);
31+export const point = needBuilder(() => {
32+ throw new Error(BRIDGE_ERROR.MISSING_POINT.message);
33+});
34+
24−export const pointCache = needBuilder(BRIDGE_ERROR.MISSING_POINT);
35+export const pointCache = needBuilder(() => {
36+ throw new Error(BRIDGE_ERROR.MISSING_POINT.message);
37+});
38+
25export const fromPointCache = (cache, point) => {
39export const fromPointCache = (cache, point) => {
26 if (!(point in cache)) {
40 if (!(point in cache)) {
27− throw BRIDGE_ERROR.MISSING_POINT;
41+ throw new Error(BRIDGE_ERROR.MISSING_POINT.message);
28 }
42 }
29
43
30 return cache[point];
44 return cache[point];
31};
45};
46+
32export const keystore = obj => {
47export const keystore = obj => {
33− const ks = needBuilder(BRIDGE_ERROR.MISSING_KEYSTORE)();
48+ const ks = needBuilder(BRIDGE_ERROR.MISSING_KEYSTORE)(obj);
34 return ks.value.matchWith({
49 return ks.value.matchWith({
35 Ok: result => result.value,
50 Ok: result => result.value,
36 Error: _ => {
51 Error: _ => {
src/lib/useRouter.js+1−5
@@ -62,12 +62,8 @@ export default function useRouter({
62 const data = useMemo(() => last(routes).data, [routes]);
62 const data = useMemo(() => last(routes).data, [routes]);
63 const Route = useMemo(() => views[peek().key], [views, peek]);
63 const Route = useMemo(() => views[peek().key], [views, peek]);
64
64
65− // Scroll to top of page with each route transition on primary navigation
65+ // Scroll to top of page with each route transition
66 useEffect(() => {
66 useEffect(() => {
67− if (!primary) {
68− return;
69− }
70−
71 window.scrollTo(0, 0);
67 window.scrollTo(0, 0);
72 }, [routes, primary]);
68 }, [routes, primary]);
73
69
src/lib/validators.js+1−1
@@ -29,7 +29,7 @@ export const simpleValidatorWrapper = ({
29 // Run the validator and return the result.
29 // Run the validator and return the result.
30 const pass = validator(prevMessage.data);
30 const pass = validator(prevMessage.data);
31 const data = pass ? transform(prevMessage.data) : prevMessage.data;
31 const data = pass ? transform(prevMessage.data) : prevMessage.data;
32− console.log(pass, data);
32+
33 return newMessage(data, pass, !pass && error);
33 return newMessage(data, pass, !pass && error);
34};
34};
35
35
src/lib/walletgen.js+5−2
@@ -10,6 +10,7 @@ import {
10 GALAXY_ENTROPY_BITS,
10 GALAXY_ENTROPY_BITS,
11 STAR_ENTROPY_BITS,
11 STAR_ENTROPY_BITS,
12 PLANET_ENTROPY_BITS,
12 PLANET_ENTROPY_BITS,
13+ ZOD,
13} from './constants';
14} from './constants';
14
15
15const SEED_LENGTH_BYTES = SEED_ENTROPY_BITS / 8;
16const SEED_LENGTH_BYTES = SEED_ENTROPY_BITS / 8;
@@ -66,10 +67,12 @@ export const generateWallet = async (point, ticket, boot) => {
66export const generateOwnershipWallet = (ship, ticket) =>
67export const generateOwnershipWallet = (ship, ticket) =>
67 kg.generateOwnershipWallet({ ship, ticket });
68 kg.generateOwnershipWallet({ ship, ticket });
68
69
70+// ~zod is a constant in temporary wallets used for invitations
71+export const generateTemporaryOwnershipWallet = ticket =>
72+ generateOwnershipWallet(ZOD, ticket);
69export const generateTemporaryTicketAndWallet = async point => {
73export const generateTemporaryTicketAndWallet = async point => {
70 const ticket = await makeTicket(point);
74 const ticket = await makeTicket(point);
71− // ~zod is used as a constant here
72− const owner = await generateOwnershipWallet(0, ticket);
75+ const owner = await generateOwnershipWallet(ZOD, ticket);
73
76
74 return { ticket, owner };
77 return { ticket, owner };
75};
78};
src/store/lib/useBirthdaysStore.js+6
@@ -45,6 +45,12 @@ export default function useBirthdayStore() {
45 addToBirthdayCache({
45 addToBirthdayCache({
46 [point]: Maybe.Just(new Date(block.timestamp * 1000)),
46 [point]: Maybe.Just(new Date(block.timestamp * 1000)),
47 });
47 });
48+ } else {
49+ // TODO: better encoding for "no birthday" state?
50+ // if there's no birthday, just use today
51+ addToBirthdayCache({
52+ [point]: Maybe.Just(new Date()),
53+ });
48 }
54 }
49 },
55 },
50 [contracts, web3, addToBirthdayCache, getBirthday]
56 [contracts, web3, addToBirthdayCache, getBirthday]
src/style/indigo-proposals.scss+4
@@ -31,3 +31,7 @@
31.outline-none {
31.outline-none {
32 outline: none;
32 outline: none;
33}
33}
34+
35+.us-none {
36+ user-select: none;
37+}
src/views/AcceptTransfer.js+2−2
@@ -25,7 +25,7 @@ class AcceptTransfer extends React.Component {
25 super(props);
25 super(props);
26
26
27 const receivingAddress = need.addressFromWallet(props.wallet);
27 const receivingAddress = need.addressFromWallet(props.wallet);
28− const incomingPoint = need.pointCursor(props.pointCursor);
28+ const incomingPoint = need.point(props.pointCursor);
29
29
30 this.state = {
30 this.state = {
31 receivingAddress: receivingAddress,
31 receivingAddress: receivingAddress,
@@ -46,7 +46,7 @@ class AcceptTransfer extends React.Component {
46 const { state, props } = this;
46 const { state, props } = this;
47
47
48 const validContracts = need.contracts(props.contracts);
48 const validContracts = need.contracts(props.contracts);
49− const validPoint = need.pointCursor(props.pointCursor);
49+ const validPoint = need.point(props.pointCursor);
50 //TODO state.incomingPoint ?
50 //TODO state.incomingPoint ?
51
51
52 return Just(
52 return Just(
src/views/Activate.js+29−51
@@ -1,61 +1,39 @@
1−import React, { useCallback } from 'react';
1+import React from 'react';
2−import * as ob from 'urbit-ob';
3−import Maybe from 'folktale/maybe';
4−import useImpliedPoint from 'lib/useImpliedPoint';
5−import { usePointInput, useTicketInput } from 'components/Inputs';
6−import { Grid, Input } from 'indigo-react';
7
2
8−import View from 'components/View';
3+import useRouter from 'lib/useRouter';
9−import Footer from 'components/Footer';
10−import { ForwardButton } from 'components/Buttons';
11−import Passport from 'components/Passport';
12
4
13−import { useHistory } from 'store/history';
5+import { ActivateFlowProvider } from './Activate/ActivateFlow';
6+import useActivateFlowState from './Activate/useActivateFlowState';
7+import ActivateCode from './Activate/ActivateCode';
8+import ActivateDisclaimer from './Activate/ActivateDisclaimer';
9+import { LocalRouterProvider } from 'lib/LocalRouter';
10+import ActivatePassport from './Activate/ActivatePassport';
14
11
15−import { ROUTE_NAMES } from 'lib/routeNames';
12+const kActivateNames = {
16−import { useSyncKnownPoints } from 'lib/useSyncPoints';
13+ CODE: 'CODE',
17−import patp2dec from 'lib/patp2dec';
14+ DISCLAIMER: 'DISCLAIMER',
15+ PASSPORT: 'PASSPORT',
16+};
18
17
19−export default function Activate() {
18+const kActivateViews = {
20− const { popAndPush } = useHistory();
19+ [kActivateNames.CODE]: ActivateCode,
21− const impliedPoint = useImpliedPoint();
20+ [kActivateNames.DISCLAIMER]: ActivateDisclaimer,
22−
21+ [kActivateNames.PASSPORT]: ActivatePassport,
23− const pointInput = usePointInput({
24− name: 'point',
25− initialValue: impliedPoint || '',
26− autoFocus: !!impliedPoint,
27− });
22+};
28−
29− // Maybe<number>
30− const point = ob.isValidPatp(pointInput.data)
31− ? Maybe.Just(patp2dec(pointInput.data))
32− : Maybe.Nothing();
33
23
34− useSyncKnownPoints([point.getOrElse(null)].filter(p => p !== null));
24+export default function Activate() {
35−
25+ const state = useActivateFlowState();
36− const ticketInput = useTicketInput({
26+ const { Route, ...router } = useRouter({
37− name: 'ticket',
27+ names: kActivateNames,
28+ views: kActivateViews,
29+ initialRoutes: [{ key: kActivateNames.CODE }],
38 });
30 });
39
31
40− const goToLogin = useCallback(() => popAndPush(ROUTE_NAMES.LOGIN), [
41− popAndPush,
42− ]);
43−
44 return (
32 return (
45− <View>
33+ <LocalRouterProvider value={router}>
46− <Grid>
34+ <ActivateFlowProvider value={state}>
47− <Grid.Item as={Passport} point={point} full />
35+ <Route />
48− {!impliedPoint && <Grid.Item as={Input} {...pointInput} full />}
36+ </ActivateFlowProvider>
49− <Grid.Item as={Input} {...ticketInput} full />
37+ </LocalRouterProvider>
50− </Grid>
51− <Footer>
52− <Grid className="pt2">
53− <Grid.Divider />
54− <Grid.Item as={ForwardButton} onClick={goToLogin} full>
55− Login
56− </Grid.Item>
57− </Grid>
58− </Footer>
59− </View>
60 );
38 );
61}
39}
src/views/Activate/ActivateCode.jsnew file+163
@@ -0,0 +1,163 @@
1+import React, { useCallback, useEffect, useState } from 'react';
2+import * as azimuth from 'azimuth-js';
3+import Maybe from 'folktale/maybe';
4+import { useTicketInput } from 'components/Inputs';
5+import { Grid, Input, H4, ErrorText } from 'indigo-react';
6+
7+import View from 'components/View';
8+import { ForwardButton, OfflineButton } from 'components/Buttons';
9+import Passport from 'components/Passport';
10+
11+import { useHistory } from 'store/history';
12+
13+import * as need from 'lib/need';
14+import { ROUTE_NAMES } from 'lib/routeNames';
15+import { useSyncKnownPoints } from 'lib/useSyncPoints';
16+import FooterButton from 'components/FooterButton';
17+import Blinky from 'components/Blinky';
18+import { DEFAULT_HD_PATH, walletFromMnemonic } from 'lib/wallet';
19+import { useNetwork } from 'store/network';
20+import { generateWallet } from 'lib/invite';
21+import { generateTemporaryOwnershipWallet } from 'lib/walletgen';
22+import { useActivateFlow } from './ActivateFlow';
23+import { useLocalRouter } from 'lib/LocalRouter';
24+
25+export default function ActivateCode() {
26+ const history = useHistory();
27+ const { names, push } = useLocalRouter();
28+ const { contracts } = useNetwork();
29+ const [generalError, setGeneralError] = useState();
30+ const [deriving, setDeriving] = useState(false);
31+ const {
32+ derivedWallet,
33+ setDerivedWallet,
34+ setInviteWallet,
35+ derivedPoint,
36+ setDerivedPoint,
37+ } = useActivateFlow();
38+
39+ const ticketInput = useTicketInput({
40+ name: 'ticket',
41+ label: 'Code',
42+ autoFocus: true,
43+ });
44+ const validTicket = ticketInput.pass;
45+
46+ const goToLogin = useCallback(() => history.popAndPush(ROUTE_NAMES.LOGIN), [
47+ history,
48+ ]);
49+ const goToDisclaimer = useCallback(() => push(names.DISCLAIMER), [
50+ names,
51+ push,
52+ ]);
53+
54+ const pass = derivedWallet.matchWith({
55+ Nothing: () => false,
56+ Just: () => true,
57+ });
58+
59+ useEffect(() => {
60+ if (validTicket) {
61+ const _contracts = need.contracts(contracts);
62+
63+ setDeriving(true);
64+ // when the ticket becomes valid, derive the point
65+ (async () => {
66+ const { seed } = await generateTemporaryOwnershipWallet(
67+ ticketInput.data
68+ );
69+
70+ //TODO isn't all this accessible in the ownership object?
71+ const inviteWallet = walletFromMnemonic(
72+ seed,
73+ DEFAULT_HD_PATH
74+ ).matchWith({
75+ Just: w => w.value,
76+ Nothing: () => {
77+ setGeneralError('Derivation Error: invalid derived seed.');
78+ throw new Error();
79+ },
80+ });
81+
82+ const incoming = await azimuth.azimuth.getTransferringFor(
83+ _contracts,
84+ inviteWallet.address
85+ );
86+
87+ let realPoint = Maybe.Nothing();
88+ let realWallet = Maybe.Nothing();
89+
90+ if (incoming.length > 0) {
91+ let pointNum = parseInt(incoming[0], 10);
92+ realPoint = Maybe.Just(pointNum);
93+
94+ const genWallet = await generateWallet(pointNum);
95+
96+ realWallet = Maybe.Just(genWallet);
97+ if (incoming.length > 1) {
98+ setGeneralError(
99+ 'This invite code has multiple points available.\n' +
100+ "Once you've activated this point, activate the next with the same process."
101+ );
102+ }
103+ } else {
104+ setGeneralError(
105+ 'Invite code has no claimable point.\n' +
106+ 'Check your invite code and try again?'
107+ );
108+ }
109+
110+ setDerivedPoint(realPoint);
111+ setDerivedWallet(realWallet);
112+ setInviteWallet(Maybe.Just(inviteWallet));
113+ setDeriving(false);
114+ })();
115+ } else {
116+ setGeneralError(false);
117+ }
118+ }, [
119+ validTicket,
120+ contracts,
121+ ticketInput.data,
122+ setDerivedPoint,
123+ setDerivedWallet,
124+ setInviteWallet,
125+ ]);
126+
127+ // when we know the derived point, ensure we have the data to display it
128+ useSyncKnownPoints([derivedPoint.getOrElse(null)].filter(p => p !== null));
129+
130+ return (
131+ <View>
132+ <Grid>
133+ <Grid.Item as={Passport} point={derivedPoint} full />
134+ <Grid.Item as={H4} className="mt3 mb2" full>
135+ Activate
136+ </Grid.Item>
137+ <Grid.Item as={Input} {...ticketInput} full />
138+ {generalError && (
139+ <Grid.Item full>
140+ <ErrorText>{generalError}</ErrorText>{' '}
141+ </Grid.Item>
142+ )}
143+ <Grid.Item
144+ as={ForwardButton}
145+ className="mt4"
146+ disabled={!pass || deriving}
147+ accessory={deriving ? <Blinky /> : null}
148+ onClick={goToDisclaimer}
149+ solid
150+ full>
151+ {deriving && 'Deriving...'}
152+ {!deriving && 'Go'}
153+ </Grid.Item>
154+ <Grid.Divider className="mt3" />
155+ <Grid.Item as={ForwardButton} onClick={goToLogin} full>
156+ Login
157+ </Grid.Item>
158+ <Grid.Divider />
159+ </Grid>
160+ <FooterButton as={OfflineButton} />
161+ </View>
162+ );
163+}
src/views/Activate/ActivateDisclaimer.jsnew file+83
@@ -0,0 +1,83 @@
1+import React, { useCallback } from 'react';
2+import { Grid, H3, P, B, Flex, Text, CheckboxInput } from 'indigo-react';
3+
4+import View from 'components/View';
5+import { useCheckboxInput } from 'components/Inputs';
6+import { ForwardButton } from 'components/Buttons';
7+import { useLocalRouter } from 'lib/LocalRouter';
8+
9+export default function ActivateDisclaimer() {
10+ const { push, names } = useLocalRouter();
11+ const checkboxInput = useCheckboxInput({
12+ name: 'checkbox',
13+ label: 'I acknowledge and understand these rights',
14+ });
15+
16+ const goToPassport = useCallback(() => push(names.PASSPORT), [push, names]);
17+
18+ return (
19+ <View>
20+ <Grid gap={2} className="mt8 mb10">
21+ <Grid.Item as={H3} full>
22+ Disclaimer
23+ </Grid.Item>
24+ <Grid.Item full>
25+ <P>
26+ Welcome to Bridge. Please read this information. Your assets could
27+ be stolen if you do not pay attention to these warnings.
28+ </P>
29+
30+ <P>
31+ <B>You own and control your assets. We do not.</B> If you send your
32+ assets to another address, we can’t get them back for you.
33+ </P>
34+
35+ <B>Please understand that nobody can:</B>
36+ <P>
37+ 1. Access your assets for you <br />
38+ 2. Recover, reset, or modify ANY of your information <br />
39+ 3. Reverse, cancel, or refund transactions <br />
40+ 4. Hold, back-up, or access your keys
41+ </P>
42+
43+ <B>
44+ You’re responsible for keeping your information safe. This includes:
45+ </B>
46+ <P>
47+ 1. Private Keys/Mnemonic Phrases and passwords <br />
48+ 2. JSON files <br />
49+ 3. Hardware wallet PINs; <br />
50+ 4. Downloading this software from a reliable site, and ensuring it
51+ has not been tampered with. [add something about using the checksum
52+ here]
53+ </P>
54+
55+ <B>To be clear</B>
56+ <P>
57+ This software is provided “as is” without warranties of any kind and
58+ our liability to you in connection with the same is limited;
59+ </P>
60+ <P>
61+ We have no liability for any security problems or incidents that you
62+ may experience, including any loss or theft of your keys or any
63+ problems that may arise in connection with your wallet.
64+ </P>
65+ </Grid.Item>
66+ <Grid.Item as={Flex} className="bg-red1 pv3 ph4" align="center" full>
67+ <Text className="red3 fw-bold">
68+ Warning: We Can't Restore of Reset Your Master Ticket
69+ </Text>
70+ </Grid.Item>
71+ <Grid.Item as={CheckboxInput} {...checkboxInput} full />
72+ <Grid.Item
73+ as={ForwardButton}
74+ disabled={!checkboxInput.data}
75+ onClick={goToPassport}
76+ solid
77+ full>
78+ Continue
79+ </Grid.Item>
80+ </Grid>
81+ </View>
82+ );
83+}
src/views/Activate/ActivateFlow.jsnew file+9
@@ -0,0 +1,9 @@
1+import { createContext, useContext } from 'react';
2+
3+export const ActivateFlowContext = createContext(null);
4+export const ActivateFlowProvider = ActivateFlowContext.Provider;
5+
6+// Hook version
7+export function useActivateFlow() {
8+ return useContext(ActivateFlowContext);
9+}
src/views/Activate/ActivatePassport.jsnew file+82
@@ -0,0 +1,82 @@
1+import React, { useCallback, useState } from 'react';
2+import Maybe from 'folktale/maybe';
3+import { Grid, H4, P } from 'indigo-react';
4+import PaperCollateralRenderer from 'PaperCollateralRenderer';
5+
6+import * as need from 'lib/need';
7+import { useLocalRouter } from 'lib/LocalRouter';
8+
9+import View from 'components/View';
10+import { ForwardButton, DownloadButton } from 'components/Buttons';
11+import Passport from 'components/Passport';
12+
13+import { useActivateFlow } from './ActivateFlow';
14+import { downloadWallet } from 'lib/invite';
15+
16+export default function ActivatePassport() {
17+ const { push, names } = useLocalRouter();
18+ const { derivedPoint, derivedWallet } = useActivateFlow();
19+ // const point = need.point(derivedPoint);
20+ const wallet = need.wallet(derivedWallet);
21+
22+ const [paper, setPaper] = useState(Maybe.Nothing());
23+
24+ const goToPassport = useCallback(() => push(names.PASSPORT), [push, names]);
25+
26+ const pointAsString = derivedPoint.matchWith({
27+ Nothing: () => '',
28+ Just: p => p.value.toFixed(),
29+ });
30+
31+ const generated = paper.matchWith({
32+ Nothing: () => false,
33+ Just: () => true,
34+ });
35+
36+ const download = useCallback(() => downloadWallet(paper.getOrElse([])), [
37+ paper,
38+ ]);
39+
40+ return (
41+ <View.Full>
42+ <Grid gap={10} className="mt8 mb10" align="center">
43+ <Grid.Item half={1} alignSelf="center">
44+ <Passport point={derivedPoint} ticket={generated} />
45+ </Grid.Item>
46+ <Grid.Item half={2} as={Grid} gap={5} alignSelf="center">
47+ <Grid.Item full>Step 1 of 3</Grid.Item>
48+ <Grid.Item full as={H4}>
49+ Passport
50+ </Grid.Item>
51+ <Grid.Item full as={P}>
52+ After you’ve downloaded your passport, back up the ticket manually
53+ or store on a trusted device.
54+ </Grid.Item>
55+ <Grid.Item full as={P}>
56+ What is digital identity? A passport is your digital identity. You
57+ will use your passport to access your true computer, send payments,
58+ and administer your identity. So naturally, you must keep this
59+ secure.
60+ </Grid.Item>
61+ <Grid.Item
62+ full
63+ as={DownloadButton}
64+ disabled={!generated}
65+ onClick={download}
66+ solid>
67+ Download Passport
68+ </Grid.Item>
69+ </Grid.Item>
70+ </Grid>
71+ <PaperCollateralRenderer
72+ className="super-hidden"
73+ wallet={{ [pointAsString]: wallet }}
74+ callback={data => {
75+ console.log(data);
76+ setPaper(Maybe.Just(data));
77+ }}
78+ mode="REGISTRATION"
79+ />
80+ </View.Full>
81+ );
82+}
src/views/Activate/useActivateFlowState.jsnew file+17
@@ -0,0 +1,17 @@
1+import { useState } from 'react';
2+import Maybe from 'folktale/maybe';
3+
4+export default function useActivateFlowState() {
5+ const [derivedWallet, setDerivedWallet] = useState(Maybe.Nothing());
6+ const [inviteWallet, setInviteWallet] = useState(Maybe.Nothing());
7+ const [derivedPoint, setDerivedPoint] = useState(Maybe.Nothing());
8+
9+ return {
10+ derivedWallet,
11+ setDerivedWallet,
12+ inviteWallet,
13+ setInviteWallet,
14+ derivedPoint,
15+ setDerivedPoint,
16+ };
17+}
src/views/CancelTransfer.js+2−2
@@ -17,7 +17,7 @@ class CancelTransfer extends React.Component {
17 constructor(props) {
17 constructor(props) {
18 super(props);
18 super(props);
19
19
20− const pointInTransfer = need.pointCursor(props.pointCursor);
20+ const pointInTransfer = need.point(props.pointCursor);
21
21
22 this.state = {
22 this.state = {
23 proxyAddress: '',
23 proxyAddress: '',
@@ -31,7 +31,7 @@ class CancelTransfer extends React.Component {
31 const { props } = this;
31 const { props } = this;
32
32
33 const validContracts = need.contracts(props.contracts);
33 const validContracts = need.contracts(props.contracts);
34− const validPoint = need.pointCursor(props.pointCursor);
34+ const validPoint = need.point(props.pointCursor);
35 //TODO this.state.pointInTransfer ?
35 //TODO this.state.pointInTransfer ?
36
36
37 const txn = azimuth.ecliptic.setTransferProxy(
37 const txn = azimuth.ecliptic.setTransferProxy(
src/views/GenKeyfile.js+1−1
@@ -27,7 +27,7 @@ class GenKeyfile extends React.Component {
27 }
27 }
28
28
29 getPointDetails() {
29 getPointDetails() {
30− const point = need.pointCursor(this.props.pointCursor);
30+ const point = need.point(this.props.pointCursor);
31 const pointDetails = need.fromPointCache(this.props.pointCache, point);
31 const pointDetails = need.fromPointCache(this.props.pointCache, point);
32
32
33 // in case we did SetKeys earlier this session, make sure to generate the
33 // in case we did SetKeys earlier this session, make sure to generate the
src/views/Invite.js+1−1
@@ -37,7 +37,7 @@ export default function Invite() {
37 initialRoutes: [{ key: kInviteNames.URL }],
37 initialRoutes: [{ key: kInviteNames.URL }],
38 });
38 });
39 const { pointCursor } = usePointCursor();
39 const { pointCursor } = usePointCursor();
40− const point = need.pointCursor(pointCursor);
40+ const point = need.point(pointCursor);
41 const name = useCurrentPointName();
41 const name = useCurrentPointName();
42
42
43 // sync the current point
43 // sync the current point
src/views/Invite/InviteEmail.js+3−3
@@ -100,7 +100,7 @@ export default function InviteEmail() {
100 const { wallet, walletType, walletHdPath } = useWallet();
100 const { wallet, walletType, walletHdPath } = useWallet();
101 const { syncInvites, getInvites } = usePointCache();
101 const { syncInvites, getInvites } = usePointCache();
102 const { pointCursor } = usePointCursor();
102 const { pointCursor } = usePointCursor();
103− const point = need.pointCursor(pointCursor);
103+ const point = need.point(pointCursor);
104 const { getHasRecieved, syncHasReceivedForEmail, sendMail } = useMailer();
104 const { getHasRecieved, syncHasReceivedForEmail, sendMail } = useMailer();
105
105
106 const { availableInvites } = getInvites(point);
106 const { availableInvites } = getInvites(point);
@@ -391,7 +391,7 @@ export default function InviteEmail() {
391 }, [isDone, syncInvites, point]);
391 }, [isDone, syncInvites, point]);
392
392
393 return (
393 return (
394− <Grid gap={12}>
394+ <Grid gap={3}>
395 <Grid.Item as={Grid} full>
395 <Grid.Item as={Grid} full>
396 <Grid.Item as={Flex} cols={[1, 11]} align="center">
396 <Grid.Item as={Flex} cols={[1, 11]} align="center">
397 <MiniBackButton onClick={() => pop()} />
397 <MiniBackButton onClick={() => pop()} />
@@ -432,7 +432,7 @@ export default function InviteEmail() {
432 <Grid.Item
432 <Grid.Item
433 key={input.name}
433 key={input.name}
434 as={Grid}
434 as={Grid}
435− gap={12}
435+ gap={3}
436 onMouseOver={() => setHovered({ [input.name]: true })}
436 onMouseOver={() => setHovered({ [input.name]: true })}
437 onMouseLeave={() => setHovered({ [input.name]: false })}
437 onMouseLeave={() => setHovered({ [input.name]: false })}
438 full>
438 full>
src/views/Invite/InviteUrl.js+1−1
@@ -13,7 +13,7 @@ import FooterButton from 'components/FooterButton';
13export default function InviteUrl() {
13export default function InviteUrl() {
14 const { names, push } = useLocalRouter();
14 const { names, push } = useLocalRouter();
15 const { pointCursor } = usePointCursor();
15 const { pointCursor } = usePointCursor();
16− const point = need.pointCursor(pointCursor);
16+ const point = need.point(pointCursor);
17 const { availableInvites } = useInvites(point);
17 const { availableInvites } = useInvites(point);
18 const canInvite = availableInvites.matchWith({
18 const canInvite = availableInvites.matchWith({
19 Nothing: () => false,
19 Nothing: () => false,
src/views/InvitesManage.js+1−1
@@ -39,7 +39,7 @@ class InvitesManage extends React.Component {
39 }
39 }
40
40
41 componentDidMount() {
41 componentDidMount() {
42− this.point = need.pointCursor(this.props.pointCursor);
42+ this.point = need.point(this.props.pointCursor);
43 this.contracts = need.contracts(this.props.contracts);
43 this.contracts = need.contracts(this.props.contracts);
44
44
45 azimuth.azimuth
45 azimuth.azimuth
src/views/IssueChild.js+1−1
@@ -40,7 +40,7 @@ class IssueChild extends React.Component {
40 constructor(props) {
40 constructor(props) {
41 super(props);
41 super(props);
42
42
43− const issuingPoint = need.pointCursor(props.pointCursor);
43+ const issuingPoint = need.point(props.pointCursor);
44
44
45 const getCandidate = () => ob.patp(getSpawnCandidate(issuingPoint));
45 const getCandidate = () => ob.patp(getSpawnCandidate(issuingPoint));
46
46
src/views/Point.js+1−1
@@ -24,7 +24,7 @@ export default function Point() {
24 const { pointCursor } = usePointCursor();
24 const { pointCursor } = usePointCursor();
25 const { wallet } = useWallet();
25 const { wallet } = useWallet();
26
26
27− const point = need.pointCursor(pointCursor);
27+ const point = need.point(pointCursor);
28
28
29 // fetch the invites for the current cursor
29 // fetch the invites for the current cursor
30 const { availableInvites } = useInvites(point);
30 const { availableInvites } = useInvites(point);
src/views/Point/Actions.js+1−1
@@ -19,7 +19,7 @@ function Actions() {
19 const history = useHistory();
19 const history = useHistory();
20 const { wallet } = useWallet();
20 const { wallet } = useWallet();
21 const { pointCursor } = usePointCursor();
21 const { pointCursor } = usePointCursor();
22− const point = need.pointCursor(pointCursor);
22+ const point = need.point(pointCursor);
23 const { getDetails } = usePointCache();
23 const { getDetails } = usePointCache();
24 const pointDetails = getDetails(point);
24 const pointDetails = getDetails(point);
25
25
src/views/SetKeys.js+2−2
@@ -22,7 +22,7 @@ class SetKeys extends React.Component {
22 constructor(props) {
22 constructor(props) {
23 super(props);
23 super(props);
24
24
25− const point = need.pointCursor(props.pointCursor);
25+ const point = need.point(props.pointCursor);
26
26
27 this.state = {
27 this.state = {
28 auth: '',
28 auth: '',
@@ -115,7 +115,7 @@ class SetKeys extends React.Component {
115 const { state, props } = this;
115 const { state, props } = this;
116
116
117 const validContracts = need.contracts(props.contracts);
117 const validContracts = need.contracts(props.contracts);
118− const validPoint = need.pointCursor(props.pointCursor);
118+ const validPoint = need.point(props.pointCursor);
119
119
120 // TODO: move this to a lib for validating things
120 // TODO: move this to a lib for validating things
121 const hexRegExp = /[0-9A-Fa-f]{64}/g;
121 const hexRegExp = /[0-9A-Fa-f]{64}/g;
src/views/SetProxy.js+2−2
@@ -29,7 +29,7 @@ class _SetProxy extends React.Component {
29 constructor(props) {
29 constructor(props) {
30 super(props);
30 super(props);
31
31
32− const issuingPoint = need.pointCursor(props.pointCursor);
32+ const issuingPoint = need.point(props.pointCursor);
33
33
34 this.state = {
34 this.state = {
35 proxyAddress: '',
35 proxyAddress: '',
@@ -61,7 +61,7 @@ class _SetProxy extends React.Component {
61 const { state, props } = this;
61 const { state, props } = this;
62
62
63 const validContracts = need.contracts(props.contracts);
63 const validContracts = need.contracts(props.contracts);
64− const validPoint = need.pointCursor(props.pointCursor);
64+ const validPoint = need.point(props.pointCursor);
65
65
66 const txArgs = [validContracts, validPoint, state.proxyAddress];
66 const txArgs = [validContracts, validPoint, state.proxyAddress];
67
67
src/views/Transfer.js+2−2
@@ -20,7 +20,7 @@ class Transfer extends React.Component {
20 constructor(props) {
20 constructor(props) {
21 super(props);
21 super(props);
22
22
23− const issuingPoint = need.pointCursor(props.pointCursor);
23+ const issuingPoint = need.point(props.pointCursor);
24
24
25 this.state = {
25 this.state = {
26 receivingAddress: '',
26 receivingAddress: '',
@@ -47,7 +47,7 @@ class Transfer extends React.Component {
47 const { state, props } = this;
47 const { state, props } = this;
48
48
49 const validContracts = need.contracts(props.contracts);
49 const validContracts = need.contracts(props.contracts);
50− const validPoint = need.pointCursor(props.pointCursor);
50+ const validPoint = need.point(props.pointCursor);
51
51
52 const txn = azimuth.ecliptic.setTransferProxy(
52 const txn = azimuth.ecliptic.setTransferProxy(
53 validContracts,
53 validContracts,