on master help sign in
Merge pull request #210 from urbit/mino-more-fixes
a017d40Fang
package-lock.json+5−4
@@ -2658,12 +2658,13 @@
2658 }
2658 }
2659 },
2659 },
2660 "azimuth-js": {
2660 "azimuth-js": {
2661− "version": "0.15.0",
2661+ "version": "0.15.1",
2662− "resolved": "https://registry.npmjs.org/azimuth-js/-/azimuth-js-0.15.0.tgz",
2662+ "resolved": "https://registry.npmjs.org/azimuth-js/-/azimuth-js-0.15.1.tgz",
2663− "integrity": "sha512-U/700d/94vvjDXpfXVPhrmYna3EX4aVRfkAdG21+k54LJTEozKAQySTPiuOpNsn9kEjaAp3sHR+C9glxm+5NEg==",
2663+ "integrity": "sha512-EEjDPlv4LQcgF5xhRQg2o81IrcVCu+3K87AI/NVRl37rcQyTCrCzjfeafOTqUQ8PvQXk+wf0Vrtrc+80yJju4g==",
2664 "requires": {
2664 "requires": {
2665 "azimuth-solidity": "1.2.0",
2665 "azimuth-solidity": "1.2.0",
2666− "ethereumjs-util": "^5.2.0"
2666+ "ethereumjs-util": "^5.2.0",
2667+ "urbit-ob": "^4.0.1"
2667 }
2668 }
2668 },
2669 },
2669 "azimuth-solidity": {
2670 "azimuth-solidity": {
package.json+1−1
@@ -19,7 +19,7 @@
19 "@ledgerhq/hw-transport-u2f": "^4.61.0",
19 "@ledgerhq/hw-transport-u2f": "^4.61.0",
20 "PaperCollateralRenderer": "github:urbit/PaperCollateralRenderer",
20 "PaperCollateralRenderer": "github:urbit/PaperCollateralRenderer",
21 "async-retry": "^1.2.3",
21 "async-retry": "^1.2.3",
22− "azimuth-js": "^0.15.0",
22+ "azimuth-js": "^0.15.1",
23 "azimuth-solidity": "^1.2.0",
23 "azimuth-solidity": "^1.2.0",
24 "bip32": "^1.0.2",
24 "bip32": "^1.0.2",
25 "bip39": "^2.5.0",
25 "bip39": "^2.5.0",
src/components/Passport.js+2−2
@@ -30,7 +30,7 @@ const VISIBLE_ADDRESS_CHAR_COUNT = 20;
30const EMPTY_ADDRESS = times(VISIBLE_ADDRESS_CHAR_COUNT, () => '<').join('');
30const EMPTY_ADDRESS = times(VISIBLE_ADDRESS_CHAR_COUNT, () => '<').join('');
31const ADDRESS_BUFFER_CHARS = times(40, () => '<').join('');
31const ADDRESS_BUFFER_CHARS = times(40, () => '<').join('');
32
32
33−const INVERTED_COLORWAY = ['#000', '#fff', '#000'];
33+const INVERTED_COLORWAY = ['#fff', '#000'];
34
34
35const buildKeyType = permissions => {
35const buildKeyType = permissions => {
36 if (permissions.isOwner) {
36 if (permissions.isOwner) {
@@ -142,7 +142,7 @@ Passport.Mini = function MiniPassport({ point, className, inverted, ...rest }) {
142 patp={name}
142 patp={name}
143 size={64}
143 size={64}
144 margin={0}
144 margin={0}
145− colorway={inverted ? INVERTED_COLORWAY : undefined}
145+ colors={inverted ? INVERTED_COLORWAY : undefined}
146 />
146 />
147 </Grid.Item>
147 </Grid.Item>
148 <Grid.Item as={Flex} cols={[4, 13]} col justify="between">
148 <Grid.Item as={Flex} cols={[4, 13]} col justify="between">
src/lib/child.js+3−1
@@ -5,10 +5,12 @@ const MAX_GALAXY = MIN_STAR - 1;
5const MAX_STAR = MIN_PLANET - 1;
5const MAX_STAR = MIN_PLANET - 1;
6
6
7const randomStarName = galaxy =>
7const randomStarName = galaxy =>
8+ // ( random in range 0x1 .. 0xff ) * 0x100 + 0x??
8 (Math.floor(Math.random() * MAX_GALAXY) + 1) * MIN_STAR + galaxy;
9 (Math.floor(Math.random() * MAX_GALAXY) + 1) * MIN_STAR + galaxy;
9
10
10const randomPlanetName = star =>
11const randomPlanetName = star =>
12+ // ( random in range 0x1 .. 0xffff ) * 0x10000 + 0x????
11− (Math.floor(Math.random() * MAX_STAR) + 1) * (MAX_STAR + 1) + star;
13+ (Math.floor(Math.random() * MAX_STAR) + 1) * MIN_PLANET + star;
12
14
13const getSpawnCandidate = point =>
15const getSpawnCandidate = point =>
14 point >= MIN_GALAXY && point < MIN_STAR
16 point >= MIN_GALAXY && point < MIN_STAR
src/lib/inviteMail.js+2−2
@@ -30,8 +30,8 @@ async function hasReceived(recipient) {
30 return res.hasReceived;
30 return res.hasReceived;
31}
31}
32
32
33−function sendMail(recipient, ticket, tx) {
33+function sendMail(recipient, ticket, sender, tx) {
34− return sendRequest('/send-ticket', { recipient, ticket, tx });
34+ return sendRequest('/send-ticket', { recipient, ticket, sender, tx });
35}
35}
36
36
37export { hasReceived, sendMail };
37export { hasReceived, sendMail };
src/lib/lib.js+2−1
@@ -1,4 +1,5 @@
1import * as ob from 'urbit-ob';
1import * as ob from 'urbit-ob';
2+import patp2dec from './patp2dec';
2
3
3const compose = (...fs) =>
4const compose = (...fs) =>
4 fs.reduceRight((pF, nF) => (...args) => nF(pF(...args)), v => v);
5 fs.reduceRight((pF, nF) => (...args) => nF(pF(...args)), v => v);
@@ -18,7 +19,7 @@ const fill = (n, v) => Array.from(Array(n), () => v);
18const isValidGalaxy = name => {
19const isValidGalaxy = name => {
19 let point;
20 let point;
20 try {
21 try {
21− point = parseInt(ob.patp2dec(name), 10);
22+ point = patp2dec(name);
22 } catch (err) {
23 } catch (err) {
23 return false;
24 return false;
24 }
25 }
src/lib/txn.js+2−2
@@ -1,4 +1,3 @@
1−import * as ob from 'urbit-ob';
2import Tx from 'ethereumjs-tx';
1import Tx from 'ethereumjs-tx';
3import { toWei, fromWei, toHex } from 'web3-utils';
2import { toWei, fromWei, toHex } from 'web3-utils';
4import retry from 'async-retry';
3import retry from 'async-retry';
@@ -8,6 +7,7 @@ import { ledgerSignTransaction } from './ledger';
8import { trezorSignTransaction } from './trezor';
7import { trezorSignTransaction } from './trezor';
9import { WALLET_TYPES, addHexPrefix } from './wallet';
8import { WALLET_TYPES, addHexPrefix } from './wallet';
10import { CHECK_BLOCK_EVERY_MS } from './constants';
9import { CHECK_BLOCK_EVERY_MS } from './constants';
10+import patp2dec from './patp2dec';
11
11
12const RETRY_OPTIONS = {
12const RETRY_OPTIONS = {
13 retries: 99999,
13 retries: 99999,
@@ -177,7 +177,7 @@ const getTxnInfo = async (web3, addr) => {
177// TODO(shrugs): deprecate, unifiy with other callsites
177// TODO(shrugs): deprecate, unifiy with other callsites
178const canDecodePatp = p => {
178const canDecodePatp = p => {
179 try {
179 try {
180− ob.patp2dec(p);
180+ patp2dec(p);
181 return true;
181 return true;
182 } catch (_) {
182 } catch (_) {
183 return false;
183 return false;
src/lib/useMailer.js+2−2
@@ -40,13 +40,13 @@ export default function useMailer(emails) {
40
40
41 // prefix to avoid clobbering sendMail import
41 // prefix to avoid clobbering sendMail import
42 // also throws if return value is false
42 // also throws if return value is false
43− const _sendMail = useCallback(async (email, ticket, rawTx) => {
43+ const _sendMail = useCallback(async (email, ticket, sender, rawTx) => {
44 if (STUB_MAILER) {
44 if (STUB_MAILER) {
45 console.log(`${email} - ${ticket}`);
45 console.log(`${email} - ${ticket}`);
46 return true;
46 return true;
47 }
47 }
48
48
49− return await sendMail(email, ticket, rawTx);
49+ return await sendMail(email, ticket, sender, rawTx);
50 }, []);
50 }, []);
51
51
52 return { ...hasReceivedCache, sendMail: _sendMail };
52 return { ...hasReceivedCache, sendMail: _sendMail };
src/lib/usePermissionsForPoint.js+60−61
@@ -8,9 +8,7 @@ import * as need from 'lib/need';
8import { eqAddr, isZeroAddress } from './wallet';
8import { eqAddr, isZeroAddress } from './wallet';
9
9
10const NULL_PERMISSIONS = {
10const NULL_PERMISSIONS = {
11− isPlanet: false,
11+ isActive: false,
12− isStar: false,
13− isGalaxy: false,
14 //
12 //
15 isOwner: false,
13 isOwner: false,
16 isActiveOwner: false,
14 isActiveOwner: false,
@@ -40,69 +38,70 @@ export default function usePermissionsForPoint(address, point) {
40 const { getDetails } = usePointCache();
38 const { getDetails } = usePointCache();
41 const { contracts } = useNetwork();
39 const { contracts } = useNetwork();
42
40
43− return getDetails(point).matchWith({
41+ const pointSize = azimuth.getPointSize(point);
44− Nothing: () => NULL_PERMISSIONS,
42+ const isPlanet = pointSize === azimuth.PointSize.Planet;
45− Just: ({ value: details }) => {
43+ const isStar = pointSize === azimuth.PointSize.Star;
46− const _contracts = need.contracts(contracts);
44+ const isGalaxy = pointSize === azimuth.PointSize.Galaxy;
45+ const isParent = isStar || isGalaxy;
46+ const staticPermissions = { isPlanet, isStar, isGalaxy, isParent };
47
47
48− const pointSize = azimuth.getPointSize(point);
48+ return {
49− const isPlanet = pointSize === azimuth.PointSize.Planet;
49+ ...staticPermissions,
50− const isStar = pointSize === azimuth.PointSize.Star;
50+ ...getDetails(point).matchWith({
51− const isGalaxy = pointSize === azimuth.PointSize.Galaxy;
51+ Nothing: () => NULL_PERMISSIONS,
52− const isParent = isStar || isGalaxy;
52+ Just: ({ value: details }) => {
53+ const _contracts = need.contracts(contracts);
53
54
54− const isActive = details.active;
55+ const isActive = details.active;
55
56
56− const isOwner = eqAddr(address, details.owner);
57+ const isOwner = eqAddr(address, details.owner);
57− const isActiveOwner = isOwner && isActive;
58+ const isActiveOwner = isOwner && isActive;
58− const isManagementProxy = eqAddr(address, details.managementProxy);
59+ const isManagementProxy = eqAddr(address, details.managementProxy);
59− const isSpawnProxy = eqAddr(address, details.spawnProxy);
60+ const isSpawnProxy = eqAddr(address, details.spawnProxy);
60− const isVotingProxy = eqAddr(address, details.votingProxy);
61+ const isVotingProxy = eqAddr(address, details.votingProxy);
61− const isTransferProxy = eqAddr(address, details.transferProxy);
62+ const isTransferProxy = eqAddr(address, details.transferProxy);
62
63
63− const isManagementProxySet = !isZeroAddress(details.managementProxy);
64+ const isManagementProxySet = !isZeroAddress(details.managementProxy);
64− const isSpawnProxySet = !isZeroAddress(details.spawnProxy);
65+ const isSpawnProxySet = !isZeroAddress(details.spawnProxy);
65− const isVotingProxySet = !isZeroAddress(details.votingProxy);
66+ const isVotingProxySet = !isZeroAddress(details.votingProxy);
66− const isTransferProxySet = !isZeroAddress(details.transferProxy);
67+ const isTransferProxySet = !isZeroAddress(details.transferProxy);
67
68
68− const canManage = isOwner || isManagementProxy;
69+ const canManage = isOwner || isManagementProxy;
69− const canTransfer = isOwner || isTransferProxy;
70+ const canTransfer = isOwner || isTransferProxy;
70− const canSpawn =
71+ const canSpawn =
72+ isParent &&
73+ (isOwner || isSpawnProxy) &&
71− isParent && (isOwner || isSpawnProxy) && details.keyRevisionNumber > 0;
74+ details.keyRevisionNumber > 0;
72− const canVote = isGalaxy && isActive && (isOwner || isVotingProxy);
75+ const canVote = isGalaxy && isActive && (isOwner || isVotingProxy);
73
76
74− const spawnIsDelegatedSending = eqAddr(
77+ const spawnIsDelegatedSending = eqAddr(
75− _contracts.delegatedSending.address,
78+ _contracts.delegatedSending.address,
76− details.spawnProxy
79+ details.spawnProxy
77− );
80+ );
78
81
79− return {
82+ return {
80− isPlanet,
81− isStar,
82− isGalaxy,
83− isParent,
84− //
85− isActive,
83+ isActive,
86− //
84+ //
87− isOwner,
85+ isOwner,
88− isActiveOwner,
86+ isActiveOwner,
89− isManagementProxy,
87+ isManagementProxy,
90− isSpawnProxy,
88+ isSpawnProxy,
91− isVotingProxy,
89+ isVotingProxy,
92− isTransferProxy,
90+ isTransferProxy,
93− //
91+ //
94− isManagementProxySet,
92+ isManagementProxySet,
95− isSpawnProxySet,
93+ isSpawnProxySet,
96− isVotingProxySet,
94+ isVotingProxySet,
97− isTransferProxySet,
95+ isTransferProxySet,
98− //
96+ //
99− canManage,
97+ canManage,
100− canTransfer,
98+ canTransfer,
101− canSpawn,
99+ canSpawn,
102− canVote,
100+ canVote,
103− //
101+ //
104− spawnIsDelegatedSending,
102+ spawnIsDelegatedSending,
103+ };
105− };
104+ },
106− },
105+ }),
107− });
106+ };
108}
107}
src/lib/validators.js+10
@@ -252,6 +252,16 @@ export const validateInSet = (set, error) => m =>
252 error,
252 error,
253 });
253 });
254
254
255+export const validateNameInNumberSet = (set, error) => m =>
256+ simpleValidatorWrapper({
257+ prevMessage: m,
258+ validator: p => {
259+ const num = patp2dec(p);
260+ return set.has(num);
261+ },
262+ error,
263+ });
264+
255export const validatePatpByteLength = byteLength => {
265export const validatePatpByteLength = byteLength => {
256 return validateLength(patpStringLength(byteLength));
266 return validateLength(patpStringLength(byteLength));
257};
267};
src/lib/wallet.js+1−1
@@ -104,4 +104,4 @@ export const walletFromMnemonic = (mnemonic, hdpath, passphrase) => {
104};
104};
105
105
106export const abbreviateAddress = address =>
106export const abbreviateAddress = address =>
107− `${address.slice(0, 4)}…${address.slice(-4)}`;
107+ `${address.slice(0, 6)}…${address.slice(-4)}`;
src/views/Invite/InviteEmail.js+2
@@ -1,5 +1,6 @@
1import React, { useCallback, useEffect, useMemo, useState } from 'react';
1import React, { useCallback, useEffect, useMemo, useState } from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3+import * as ob from 'urbit-ob';
3import * as azimuth from 'azimuth-js';
4import * as azimuth from 'azimuth-js';
4import {
5import {
5 Grid,
6 Grid,
@@ -340,6 +341,7 @@ export default function InviteEmail() {
340 const success = await sendMail(
341 const success = await sendMail(
341 invite.email,
342 invite.email,
342 invite.ticket,
343 invite.ticket,
344+ ob.patp(point),
343 invite.rawTx
345 invite.rawTx
344 );
346 );
345 if (!success) throw new Error('Failed to send mail');
347 if (!success) throw new Error('Failed to send mail');
src/views/IssueChild.js+8−8
@@ -21,7 +21,7 @@ import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
21import View from 'components/View';
21import View from 'components/View';
22import useLifecycle from 'lib/useLifecycle';
22import useLifecycle from 'lib/useLifecycle';
23import { usePointCursor } from 'store/pointCursor';
23import { usePointCursor } from 'store/pointCursor';
24−import { validateInSet } from 'lib/validators';
24+import { validateNameInNumberSet } from 'lib/validators';
25import { getSpawnCandidate } from 'lib/child';
25import { getSpawnCandidate } from 'lib/child';
26
26
27function useIssueChild() {
27function useIssueChild() {
@@ -54,9 +54,9 @@ export default function IssueChild() {
54 const { pointCursor } = usePointCursor();
54 const { pointCursor } = usePointCursor();
55
55
56 const _contracts = need.contracts(contracts);
56 const _contracts = need.contracts(contracts);
57− const _point = need.point(pointCursor);
57+ const _point = parseInt(need.point(pointCursor), 10);
58
58
59− const [availablePointNames, setAvailablePointNames] = useState(Nothing());
59+ const [availablePoints, setAvailablePoints] = useState(Nothing());
60
60
61 const candidates = useMemo(() => {
61 const candidates = useMemo(() => {
62 const getCandidate = () => ob.patp(getSpawnCandidate(_point));
62 const getCandidate = () => ob.patp(getSpawnCandidate(_point));
@@ -75,12 +75,12 @@ export default function IssueChild() {
75
75
76 const validators = useMemo(
76 const validators = useMemo(
77 () => [
77 () => [
78− validateInSet(
78+ validateNameInNumberSet(
79− availablePointNames.getOrElse(new Set()),
79+ availablePoints.getOrElse(new Set()),
80 'This point cannot be spawned.'
80 'This point cannot be spawned.'
81 ),
81 ),
82 ],
82 ],
83− [availablePointNames]
83+ [availablePoints]
84 );
84 );
85 const [
85 const [
86 pointNameInput,
86 pointNameInput,
@@ -91,7 +91,7 @@ export default function IssueChild() {
91 disabled: inputsLocked,
91 disabled: inputsLocked,
92 autoFocus: true,
92 autoFocus: true,
93 validators,
93 validators,
94− error: availablePointNames.matchWith({
94+ error: availablePoints.matchWith({
95 Nothing: () => 'Loading availability...',
95 Nothing: () => 'Loading availability...',
96 Just: () => undefined,
96 Just: () => undefined,
97 }),
97 }),
@@ -124,7 +124,7 @@ export default function IssueChild() {
124 return;
124 return;
125 }
125 }
126
126
127− setAvailablePointNames(Just(new Set(availablePoints.map(ob.patp))));
127+ setAvailablePoints(Just(new Set(availablePoints)));
128 })();
128 })();
129
129
130 return () => (mounted = false);
130 return () => (mounted = false);
src/views/Login/Ticket.js+4−3
@@ -20,6 +20,7 @@ import * as need from 'lib/need';
20import { WALLET_TYPES, urbitWalletFromTicket } from 'lib/wallet';
20import { WALLET_TYPES, urbitWalletFromTicket } from 'lib/wallet';
21import useImpliedPoint from 'lib/useImpliedPoint';
21import useImpliedPoint from 'lib/useImpliedPoint';
22import useLoginView from 'lib/useLoginView';
22import useLoginView from 'lib/useLoginView';
23+import patp2dec from 'lib/patp2dec';
23
24
24export default function Ticket({ className }) {
25export default function Ticket({ className }) {
25 useLoginView(WALLET_TYPES.TICKET);
26 useLoginView(WALLET_TYPES.TICKET);
@@ -100,7 +101,7 @@ export default function Ticket({ className }) {
100 }
101 }
101
102
102 const _contracts = need.contracts(contracts);
103 const _contracts = need.contracts(contracts);
103− const point = ob.patp2dec(pointName);
104+ const point = patp2dec(pointName);
104 const urbitWallet = await urbitWalletFromTicket(ticket, point, passphrase);
105 const urbitWallet = await urbitWalletFromTicket(ticket, point, passphrase);
105 const [isOwner, isTransferProxy] = await Promise.all([
106 const [isOwner, isTransferProxy] = await Promise.all([
106 azimuth.azimuth.isOwner(
107 azimuth.azimuth.isOwner(
@@ -123,7 +124,7 @@ export default function Ticket({ className }) {
123 }
124 }
124
125
125 setUrbitWallet(Just(urbitWallet));
126 setUrbitWallet(Just(urbitWallet));
126− setPointCursor(Just(ob.patp2dec(pointName)));
127+ setPointCursor(Just(point));
127 setDeriving(false);
128 setDeriving(false);
128 }, [
129 }, [
129 pointName,
130 pointName,
@@ -142,7 +143,7 @@ export default function Ticket({ className }) {
142
143
143 try {
144 try {
144 const ticket = kg.combine([s1, s2, s3]);
145 const ticket = kg.combine([s1, s2, s3]);
145− const point = ob.patp2dec(pointName);
146+ const point = patp2dec(pointName);
146 const uhdw = await urbitWalletFromTicket(ticket, point, passphrase);
147 const uhdw = await urbitWalletFromTicket(ticket, point, passphrase);
147 setUrbitWallet(Just(uhdw));
148 setUrbitWallet(Just(uhdw));
148 } catch (_) {
149 } catch (_) {
src/views/Points.js+1−1
@@ -109,7 +109,7 @@ export default function Points() {
109 );
109 );
110
110
111 const multipassPoints = [
111 const multipassPoints = [
112− ...ownedPoints,
112+ ...ownedPoints.filter(p => !outgoingPoints.includes(p)),
113 ...managingPoints,
113 ...managingPoints,
114 ...votingPoints,
114 ...votingPoints,
115 ...spawningPoints,
115 ...spawningPoints,