on master help sign in
fix: parseInt returns NaN, but we expected it to throw
commit0336a7c6a386d554039e5762af2ded6972be2fc7 authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateTue 27 Aug 2019, 11:04 (7 years ago) parent3d8d2c7
11 files changed+47−10
src/components/InlineEthereumTransaction.js+4−1 src/form/formatters.js+6−1 src/lib/convertToInt.js+17 src/lib/patp2dec.js+3−1 src/lib/trezor.js+3−1 src/lib/useKeyfileGenerator.js+2−1 src/views/Activate/ActivateCode.js+2−1 src/views/Admin/AdminEditPermissions.js+2−1 src/views/Admin/AdminNetworkingKeys.js+4−1 src/views/Admin/Reticket/ReticketExecute.js+2−1 src/views/IssueChild.js+2−1
src/components/InlineEthereumTransaction.js+4−1
@@ -23,6 +23,7 @@ import WarningBox from './WarningBox';
2323import CopyButton from './CopyButton';
2424import ProgressButton from './ProgressButton';
2525import CopiableAddress from './CopiableAddress';
26+import convertToInt from 'lib/convertToInt';
2627
2728export default function InlineEthereumTransaction({
2829 // from useEthereumTransaction.bind
@@ -191,7 +192,9 @@ export default function InlineEthereumTransaction({
191192 min="1"
192193 max="100"
193194 value={gasPrice}
194− onChange={e => setGasPrice(parseInt(e.target.value, 10))}
195+ onChange={e =>
196+ setGasPrice(convertToInt(e.target.value, 10))
197+ }
195198 />
196199 <Grid.Item
197200 full
src/form/formatters.js+6−1
@@ -1,4 +1,5 @@
11import { compose, strSplice } from 'lib/lib';
2+import convertToInt from 'lib/convertToInt';
23
34const HEX_PREFIX = '0x';
45const TICKET_MAX_BYTE_LEN = 32; // tickets can be as large as 32 bytes
@@ -48,8 +49,12 @@ export const ensureHexPrefix = s => {
4849};
4950
5051export const convertToNumber = s => {
52+ if (!s) {
53+ return s || '';
54+ }
55+
5156 try {
52− return parseInt(s, 10);
57+ return convertToInt(s, 10);
5358 } catch {
5459 return 0;
5560 }
src/lib/convertToInt.jsnew file+17
@@ -0,0 +1,17 @@
1+import { isNaN } from 'lodash';
2+
3+/**
4+ * a version of parseInt that throws for NaN
5+ * fun fact, parseInt also handles 0x-prefixed hex strings, assuming the radix
6+ * to be 16
7+ *
8+ * @throws
9+ * @returns {number}
10+ */
11+export default (num, radix) => {
12+ const res = parseInt(num, radix);
13+ if (isNaN(res)) {
14+ throw new Error('NaN');
15+ }
16+ return res;
17+};
src/lib/patp2dec.js+3−1
@@ -1,9 +1,11 @@
11import * as ob from 'urbit-ob';
22
3+import convertToInt from './convertToInt';
4+
35/**
46 * Convert a patp string into a number, or throw.
57 *
68 * @throws
79 * @return number
810 */
9−export default patp => parseInt(ob.patp2dec(patp), 10);
11+export default patp => convertToInt(ob.patp2dec(patp), 10);
src/lib/trezor.js+3−1
@@ -1,9 +1,11 @@
11import TrezorConnect from 'trezor-connect';
2+import convertToInt from './convertToInt';
23
34const TREZOR_PATH = "m/44'/60'/0'/0/x";
45
6+// handles 0x-prefixed hex string as well as number type
57const formatChainId = val =>
6− typeof val === 'number' ? val : parseInt(val.slice(2), 16); // assume 0x-prefixed hex string
8+ typeof val === 'number' ? val : convertToInt(val.slice(2), 16);
79
810const trezorSignTransaction = async (txn, hdpath) => {
911 const trezorFormattedTxn = {
src/lib/useKeyfileGenerator.js+2−1
@@ -16,6 +16,7 @@ import {
1616 compileNetworkingKey,
1717} from './keys';
1818import useCurrentPermissions from './useCurrentPermissions';
19+import convertToInt from './convertToInt';
1920
2021export default function useKeyfileGenerator(manualNetworkSeed) {
2122 const { urbitWallet, wallet, authMnemonic } = useWallet();
@@ -30,7 +31,7 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
3031 const _point = need.point(pointCursor);
3132 const _details = need.details(getDetails(_point));
3233
33− const networkRevision = parseInt(_details.keyRevisionNumber, 10);
34+ const networkRevision = convertToInt(_details.keyRevisionNumber, 10);
3435 const { isOwner, isManagementProxy } = useCurrentPermissions();
3536
3637 const hasNetworkingKeys = networkRevision > 0;
src/views/Activate/ActivateCode.js+2−1
@@ -37,6 +37,7 @@ import FormError from 'form/FormError';
3737
3838import { useActivateFlow } from './ActivateFlow';
3939import { WARNING } from 'form/helpers';
40+import convertToInt from 'lib/convertToInt';
4041
4142export default function ActivateCode() {
4243 const history = useHistory();
@@ -121,7 +122,7 @@ export default function ActivateCode() {
121122 };
122123 }
123124
124− const point = parseInt(incoming[0], 10);
125+ const point = convertToInt(incoming[0], 10);
125126
126127 setDerivedPoint(Just(point));
127128 setInviteWallet(inviteWallet);
src/views/Admin/AdminEditPermissions.js+2−1
@@ -19,6 +19,7 @@ import ViewHeader from 'components/ViewHeader';
1919import { ForwardButton } from 'components/Buttons';
2020import { matchBlinkyDate } from 'components/Blinky';
2121import CopyButton from 'components/CopyButton';
22+import convertToInt from 'lib/convertToInt';
2223
2324export default function AdminEditPermissions() {
2425 const { push, names } = useLocalRouter();
@@ -34,7 +35,7 @@ export default function AdminEditPermissions() {
3435 const isSenate = pointSize === azimuth.PointSize.Galaxy;
3536
3637 const details = need.details(getDetails(point));
37− const networkRevision = parseInt(details.keyRevisionNumber, 10);
38+ const networkRevision = convertToInt(details.keyRevisionNumber, 10);
3839 const { canManage, isOwner } = useCurrentPermissions();
3940
4041 const goSetProxy = useCallback(
src/views/Admin/AdminNetworkingKeys.js+4−1
@@ -40,6 +40,7 @@ import {
4040import BridgeForm from 'form/BridgeForm';
4141import Condition from 'form/Condition';
4242import FormError from 'form/FormError';
43+import convertToInt from 'lib/convertToInt';
4344
4445const chainKeyProp = name => d =>
4546 d[name] === CURVE_ZERO_ADDR ? Nothing() : Just(d[name]);
@@ -64,7 +65,7 @@ function useSetKeys() {
6465 const _contracts = need.contracts(contracts);
6566 const _details = need.details(getDetails(_point));
6667
67− const networkRevision = parseInt(_details.keyRevisionNumber, 10);
68+ const networkRevision = convertToInt(_details.keyRevisionNumber, 10);
6869 const randomSeed = useRef();
6970
7071 // NOTE: nd = 'nondeterministic' (can also be a 'manual' seed)
@@ -151,6 +152,8 @@ export default function AdminNetworkingKeys() {
151152 const hasKeys = details.matchWith({
152153 Nothing: () => false,
153154 Just: ({ value: details }) => parseInt(details.keyRevisionNumber, 10) > 0,
155+ // we actually don't mind the default NaN behavior of parseInt here,
156+ // since NaN > 0 === false and that's a reasonable result
154157 });
155158
156159 const {
src/views/Admin/Reticket/ReticketExecute.js+2−1
@@ -22,6 +22,7 @@ import LoadingBar from 'components/LoadingBar';
2222import Highlighted from 'components/Highlighted';
2323import { WALLET_TYPES } from 'lib/wallet';
2424import CopiableAddress from 'components/CopiableAddress';
25+import convertToInt from 'lib/convertToInt';
2526
2627const labelForProgress = progress => {
2728 if (progress <= 0) {
@@ -58,7 +59,7 @@ export default function ReticketExecute({ newWallet, setNewWallet }) {
5859 (async () => {
5960 const point = need.point(pointCursor);
6061 const details = need.details(getDetails(point));
61− const networkRevision = parseInt(details.keyRevisionNumber, 10);
62+ const networkRevision = convertToInt(details.keyRevisionNumber, 10);
6263 try {
6364 await reticketPointBetweenWallets({
6465 fromWallet: need.wallet(wallet),
src/views/IssueChild.js+2−1
@@ -29,6 +29,7 @@ import {
2929import BridgeForm from 'form/BridgeForm';
3030import FormError from 'form/FormError';
3131import CopiableAddress from 'components/CopiableAddress';
32+import convertToInt from 'lib/convertToInt';
3233
3334function useIssueChild() {
3435 const { contracts } = useNetwork();
@@ -60,7 +61,7 @@ export default function IssueChild() {
6061 const { pointCursor } = usePointCursor();
6162
6263 const _contracts = need.contracts(contracts);
63− const _point = parseInt(need.point(pointCursor), 10);
64+ const _point = convertToInt(need.point(pointCursor), 10);
6465
6566 const availablePointsPromise = useConstant(() =>
6667 azimuth.azimuth