Skip to content
This repository has been archived by the owner on Apr 25, 2024. It is now read-only.

WIP: Descriptors #340

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"prettier/prettier": "error",
"react/jsx-props-no-spreading": "off",
"react/jsx-no-bind": "off",
"react/forbid-prop-types": "off"
"react/forbid-prop-types": "off",
"import/prefer-default-export": "off"
},
"settings": {
"import/core-modules": ["test-utils"]
Expand Down
62 changes: 61 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"prettier": "^2.0.2",
"standard-version": "^9.0.0",
"vite": "^4.2.3",
"vite-plugin-node-polyfills": "^0.7.0"
"vite-plugin-node-polyfills": "^0.7.0",
"vite-plugin-wasm": "^3.2.2"
},
"scripts": {
"build": "npm run check && VITE_GIT_SHA=`git rev-parse --short HEAD` vite build",
Expand Down Expand Up @@ -100,6 +101,7 @@
"bitcoinjs-lib": "^5.1.7",
"bowser": "^2.6.1",
"buffer": "^6.0.3",
"caravan-descriptors": "file:../../caravan-descriptors",
"classnames": "^2.2.6",
"diff": "^4.0.2",
"fs-extra": "^9.0.0",
Expand Down
52 changes: 52 additions & 0 deletions src/components/Wallet/DownloadDescriptors.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { useEffect, useState } from "react";

import { useSelector } from "react-redux";
import { Button } from "@mui/material";
import { getMaskedDerivation } from "unchained-bitcoin";
import { encodeDescriptors } from "caravan-descriptors";
import { getWalletConfig } from "../../selectors/wallet";
import { downloadFile } from "../../utils";

export const DownloadDescriptors = () => {
const walletConfig = useSelector(getWalletConfig);
const [descriptors, setDescriptors] = useState({ change: "", receive: "" });

useEffect(() => {
const loadAsync = async () => {
const multisigConfig = {
requiredSigners: walletConfig.quorum.requiredSigners,
keyOrigins: walletConfig.extendedPublicKeys.map(
({ xfp, bip32Path, xpub }) => ({
xfp,
bip32Path: getMaskedDerivation({ xpub, bip32Path }),
xpub,
})
),
addressType: walletConfig.addressType,
network: walletConfig.network,
};
const { change, receive } = await encodeDescriptors(multisigConfig);
setDescriptors({ change, receive });
};
loadAsync();
}, []);

const handleDownload = () => {
if (descriptors.change) {
downloadFile(
JSON.stringify(descriptors, null, 2),
`${walletConfig.uuid}.txt`
);
}
};

return (
<Button
variant="outlined"
onClick={handleDownload}
disabled={!descriptors.change || !descriptors.receive}
>
Download Descriptors
</Button>
);
};
4 changes: 4 additions & 0 deletions src/components/Wallet/WalletConfigInteractionButtons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import PropTypes from "prop-types";
import { Button, Grid } from "@mui/material";
import { CARAVAN_CONFIG } from "./constants";
import { DownloadDescriptors } from "./DownloadDescriptors";

const WalletConfigInteractionButtons = ({ onClearFn, onDownloadFn }) => {
const handleClearClick = (e) => {
Expand All @@ -26,6 +27,9 @@ const WalletConfigInteractionButtons = ({ onClearFn, onDownloadFn }) => {
Clear Wallet
</Button>
</Grid>
<Grid item>
<DownloadDescriptors />
</Grid>
</Grid>
);
};
Expand Down
76 changes: 76 additions & 0 deletions src/components/Wallet/WalletDescriptorImporter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useEffect, useState } from "react";
import { Button } from "@mui/material";
import { useDispatch, useSelector } from "react-redux";

import { getWalletFromDescriptor, getChecksum } from "caravan-descriptors";
import {
setRequiredSigners,
setTotalSigners,
} from "../../actions/transactionActions";
import { setAddressType } from "../../actions/settingsActions";
import {
setExtendedPublicKeyImporterBIP32Path,
setExtendedPublicKeyImporterExtendedPublicKey,
setExtendedPublicKeyImporterExtendedPublicKeyRootFingerprint,
setExtendedPublicKeyImporterFinalized,
setExtendedPublicKeyImporterMethod,
setExtendedPublicKeyImporterName,
} from "../../actions/extendedPublicKeyImporterActions";
import { updateWalletUuidAction } from "../../actions/walletActions";

const importWalletDetails = (
{ keyOrigins, requiredSigners, addressType },
dispatch
) => {
dispatch(setTotalSigners(keyOrigins.length));
dispatch(setRequiredSigners(requiredSigners));
dispatch(setAddressType(addressType));
keyOrigins.forEach(({ xfp, bip32Path, xpub }, index) => {
const number = index + 1;
dispatch(setExtendedPublicKeyImporterName(number, `key_${number}_${xfp}`));
dispatch(setExtendedPublicKeyImporterMethod(number, "text"));
dispatch(setExtendedPublicKeyImporterBIP32Path(number, bip32Path));
dispatch(
setExtendedPublicKeyImporterExtendedPublicKeyRootFingerprint(number, xfp)
);
dispatch(setExtendedPublicKeyImporterExtendedPublicKey(number, xpub));
dispatch(setExtendedPublicKeyImporterFinalized(number, true));
});
};

export const WalletDescriptorImporter = () => {
const [walletConfig, setWalletConfig] = useState();
const network = useSelector((state) => state.quorum.network);
const dispatch = useDispatch();
useEffect(() => {
if (walletConfig) {
importWalletDetails(walletConfig, dispatch);
}
}, [walletConfig]);

const handleClick = async () => {
// eslint-disable-next-line no-alert
const descriptor = window.prompt(
`Please enter one of the wallet's descriptors (change or receive).
Make sure any settings that are not in a descriptor are set before submitting.`
);

if (descriptor) {
try {
const config = await getWalletFromDescriptor(descriptor, network);
const checksum = await getChecksum(descriptor);
dispatch(updateWalletUuidAction(checksum));
setWalletConfig(config);
} catch (e) {
// eslint-disable-next-line no-alert
window.alert(e.message);
}
}
};

return (
<Button color="secondary" variant="contained" onClick={handleClick}>
Import Descriptor
</Button>
);
};
15 changes: 8 additions & 7 deletions src/components/Wallet/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
SET_CLIENT_USERNAME,
} from "../../actions/clientActions";
import { clientPropTypes, slicePropTypes } from "../../proptypes";
import { WalletDescriptorImporter } from "./WalletDescriptorImporter";

class CreateWallet extends React.Component {
static validateProperties(config, properties, key) {
Expand Down Expand Up @@ -356,12 +357,7 @@ class CreateWallet extends React.Component {
type="file"
/>

<Button
color="primary"
variant="contained"
component="span"
style={{ marginTop: "20px" }}
>
<Button color="primary" variant="contained" component="span">
Import Wallet Configuration
</Button>
</label>
Expand Down Expand Up @@ -544,7 +540,12 @@ class CreateWallet extends React.Component {
<Box>
<Grid container spacing={3}>
<Grid item xs={12}>
{this.renderWalletImporter()}
<Grid container style={{ marginTop: "10px" }} spacing={3}>
<Grid item>{this.renderWalletImporter()}</Grid>
<Grid item>
<WalletDescriptorImporter />
</Grid>
</Grid>
</Grid>
<Grid item md={configuring ? 8 : 12}>
{this.renderExtendedPublicKeyImporters()}
Expand Down
13 changes: 13 additions & 0 deletions vite.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { defineConfig } from "vite";
import wasm from "vite-plugin-wasm";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";

// https://vitejs.dev/config/
export default defineConfig({
base: "/caravan/#",
assetsInclude: ["**/*.wasm"],
plugins: [
wasm(),
react(),
nodePolyfills({
protocolImports: true,
Expand All @@ -17,4 +20,14 @@ export default defineConfig({
define: {
VITE_GIT_SHA: JSON.stringify(process.env.VITE_GIT_SHA),
},
optimizeDeps: {
// needed for local development to support proper handling of wasm
exclude: ["caravan-descriptors"],
},
server: {
fs: {
// Allow serving files from one level up to the project root
allow: ["../.."],
},
},
});