Skip to content

Commit 83c3f28

Browse files
authored
Feat: bip32 package with blinded xpub support (#126)
* cleanup and fix generator templates * init bip32 package with paths utils * fix: eslint and add import ordering * split up key and path modules and add tests * custom util for getting random ints in node or browser * use custom random int for blinded paths * util for getting blinded xpub from source * feat: blind xpub support for text input * make new bip32 package publishable * feat: reused functionality extracted to a utility for getting relative child sequence
1 parent ed8a2dd commit 83c3f28

28 files changed

+2314
-119
lines changed

apps/coordinator/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"not op_mini all"
9595
],
9696
"dependencies": {
97+
"@caravan/bip32": "*",
9798
"@caravan/bitcoin": "*",
9899
"@caravan/clients": "*",
99100
"@caravan/descriptors": "^0.1.1",

apps/coordinator/src/components/Coldcard/ColdcardFileReader.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import React from "react";
33
import PropTypes from "prop-types";
44
import Dropzone from "react-dropzone";
5-
import { Buffer } from "buffer/";
5+
import { Buffer } from "buffer";
66
import { Box, Button, FormHelperText, Grid, TextField } from "@mui/material";
77
import { CloudUpload as UploadIcon } from "@mui/icons-material";
88
import { PSBT_MAGIC_HEX } from "@caravan/bitcoin";

apps/coordinator/src/components/Wallet/ExtendedPublicKeyImporter.jsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ class ExtendedPublicKeyImporter extends React.Component {
8989
<MenuItem value={TEXT}>Enter as text</MenuItem>
9090
</TextField>
9191
</FormControl>
92-
<FormControl>{this.renderImportByMethod()}</FormControl>
92+
<FormControl style={{ width: "100%" }}>
93+
{this.renderImportByMethod()}
94+
</FormControl>
9395
</div>
9496
);
9597
};

apps/coordinator/src/components/Wallet/TextExtendedPublicKeyImporter.jsx

-55
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import React, { useEffect, useState } from "react";
2+
3+
// Components
4+
import {
5+
TextField,
6+
Box,
7+
Button,
8+
Grid,
9+
Alert,
10+
AlertTitle,
11+
Typography,
12+
} from "@mui/material";
13+
import { Network, validateExtendedPublicKey } from "@caravan/bitcoin";
14+
import { getBlindedXpub } from "@caravan/bip32";
15+
import Copyable from "../Copyable";
16+
17+
const TextExtendedPublicKeyImporter = ({
18+
validateAndSetExtendedPublicKey,
19+
network,
20+
}: {
21+
validateAndSetExtendedPublicKey: (
22+
extendedPublicKey: string,
23+
errCb: (e: string) => void,
24+
) => void;
25+
network: Network;
26+
}) => {
27+
const [error, setError] = useState("");
28+
const [xpub, setXpub] = useState("");
29+
const [original, setOriginal] = useState("");
30+
const [blindedPath, setBlindedPath] = useState("");
31+
32+
const handleSubmit = () => {
33+
validateAndSetExtendedPublicKey(xpub, setError);
34+
};
35+
36+
const handleBlind = () => {
37+
setOriginal(xpub);
38+
const blinded = getBlindedXpub(xpub);
39+
setXpub(blinded.xpub);
40+
setBlindedPath(blinded.bip32Path);
41+
};
42+
43+
useEffect(() => {
44+
if (xpub) {
45+
const error = validateExtendedPublicKey(xpub, network);
46+
setError(error);
47+
}
48+
}, [xpub]);
49+
50+
return (
51+
<Box mt={2}>
52+
<TextField
53+
fullWidth
54+
name="publicKey"
55+
label="Extended Public Key"
56+
value={xpub}
57+
variant="standard"
58+
onChange={(e) => setXpub(e.target.value)}
59+
error={error !== ""}
60+
helperText={error}
61+
multiline
62+
disabled={Boolean(original && blindedPath)}
63+
/>
64+
<Grid container style={{ marginTop: "12px" }} spacing={2}>
65+
<Grid item>
66+
<Button onClick={handleSubmit} variant="contained" color="primary">
67+
Enter
68+
</Button>
69+
</Grid>
70+
<Grid item>
71+
<Button
72+
variant="outlined"
73+
color="info"
74+
disabled={!(!error && xpub)}
75+
onClick={handleBlind}
76+
>
77+
Blind
78+
</Button>
79+
</Grid>
80+
</Grid>
81+
{blindedPath && original && (
82+
<Box my={4}>
83+
<Alert variant="outlined" severity="warning">
84+
<AlertTitle>
85+
<h3 style={{ marginTop: "0px" }}>
86+
Blinded Info (IMPORTANT: Save this info)
87+
</h3>
88+
</AlertTitle>
89+
<Typography my={1}>
90+
<strong>
91+
Without the full bip32 path, your funds will be irrecoverable
92+
</strong>
93+
. This notice will disappear once you hit &quot;Enter&quot;.
94+
</Typography>
95+
<Typography variant="h6">Blinded Path:</Typography>
96+
<Copyable showIcon text={blindedPath} />
97+
<Typography variant="h6"> Source Xpub:</Typography>
98+
<Copyable showIcon text={original} />
99+
<Typography variant="h6">Blinded Xpub:</Typography>
100+
<Copyable showIcon text={xpub} />
101+
</Alert>
102+
</Box>
103+
)}
104+
</Box>
105+
);
106+
};
107+
108+
export default TextExtendedPublicKeyImporter;

0 commit comments

Comments
 (0)