Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: Add ledger ui. #3874

Merged
merged 1 commit into from
Sep 25, 2023
Merged
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
7 changes: 5 additions & 2 deletions app/actions/DaemonActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { stopNotifcations } from "./NotificationActions";
import { saveSettings, updateStateSettingsChanged } from "./SettingsActions";
import { rescanCancel, showCantCloseModal } from "./ControlActions";
import { enableTrezor } from "./TrezorActions";
import { enableLedger } from "./LedgerActions";
import {
DEX_LOGOUT_ATTEMPT,
DEX_LOGOUT_SUCCESS,
Expand Down Expand Up @@ -309,7 +310,7 @@ export const removeWallet = (selectedWallet) => (dispatch) => {
// selectedWallet = {
// label: newWalletName,
// value: {
// wallet: newWalletName, isWatchingOnly, isTrezor, isNew,
// wallet: newWalletName, isWatchingOnly, isTrezor, isLedger, isNew
// network: isTestNet ? "testnet" : "mainnet"
// }
// }
Expand All @@ -336,7 +337,8 @@ export const createWallet = (selectedWallet) => (dispatch, getState) =>
dispatch({
isWatchingOnly: selectedWallet.value.isWatchingOnly,
createNewWallet: selectedWallet.value.isNew,
isTrezor: selectedWallet.value.istrezor,
isTrezor: selectedWallet.value.isTrezor,
isLedger: selectedWallet.value.isLedger,
type: WALLETCREATED
});
dispatch(setSelectedWallet(selectedWallet));
Expand Down Expand Up @@ -509,6 +511,7 @@ export const startWallet =
confirmDexSeed
});
selectedWallet.value.isTrezor && dispatch(enableTrezor());
selectedWallet.value.isLedger && dispatch(enableLedger());
await dispatch(getVersionServiceAttempt());
await dispatch(openWalletAttempt("", false, selectedWallet));
return discoverAccountsComplete;
Expand Down
21 changes: 6 additions & 15 deletions app/actions/LedgerActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
const coin = "decred";

import * as selectors from "selectors";
import * as cfgConstants from "constants/config";

export const LDG_LEDGER_ENABLED = "LDG_LEDGER_ENABLED";
export const LDG_WALLET_CLOSED = "LDG_WALLET_CLOSED";
Expand All @@ -26,18 +25,7 @@ export const LDG_WALLET_CLOSED = "LDG_WALLET_CLOSED";
// enableLedger only sets a value in the config. Ledger connections are made
// per action then dropped.
export const enableLedger = () => (dispatch, getState) => {
const walletName = selectors.getWalletName(getState());

if (walletName) {
const config = wallet.getWalletCfg(
selectors.isTestNet(getState()),
walletName
);
config.set(cfgConstants.LEDGER, true);
}

dispatch({ type: LDG_LEDGER_ENABLED });

connect()(dispatch, getState);
};

Expand Down Expand Up @@ -143,13 +131,16 @@ export const LDG_GETWALLETCREATIONMASTERPUBKEY_SUCCESS =
"LDG_GETWALLETCREATIONMASTERPUBKEY_SUCCESS";

export const getWalletCreationMasterPubKey =
() => async (dispatch /*, getState*/) => {
() => async (dispatch, getState) => {
dispatch({ type: LDG_GETWALLETCREATIONMASTERPUBKEY_ATTEMPT });
// TODO: Enable on mainnet.
const isTestnet = true;
const isTestnet = selectors.isTestNet(getState());
if (!isTestnet) {
throw "disabled on mainnet";
}
try {
const payload = await getPubKey(isTestnet);
const hdpk = ledgerHelpers.fixPubKeyChecksum(payload);
const hdpk = ledgerHelpers.fixPubKeyChecksum(payload, isTestnet);
dispatch({ type: LDG_GETWALLETCREATIONMASTERPUBKEY_SUCCESS });
return hdpk;
} catch (error) {
Expand Down
11 changes: 0 additions & 11 deletions app/actions/TrezorActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
addressPath
} from "helpers/trezor";
import { publishTransactionAttempt } from "./ControlActions";
import * as cfgConstants from "constants/config";
import {
MODEL1_DECRED_HOMESCREEN,
MODELT_DECRED_HOMESCREEN
Expand Down Expand Up @@ -49,16 +48,6 @@ export const TRZ_TREZOR_ENABLED = "TRZ_TREZOR_ENABLED";
// enableTrezor attepts to start a connection with connect if none exist and
// connect to a trezor device.
export const enableTrezor = () => (dispatch, getState) => {
const walletName = selectors.getWalletName(getState());

if (walletName) {
const config = wallet.getWalletCfg(
selectors.isTestNet(getState()),
walletName
);
config.set(cfgConstants.TREZOR, true);
}

Comment on lines -52 to -61
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright to just set this when the wallet is created? If it trezor/ledger it will always be so. There's no reason to set it over and over.

dispatch({ type: TRZ_TREZOR_ENABLED });

if (!setListeners) {
Expand Down
12 changes: 10 additions & 2 deletions app/actions/WalletLoaderActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
getBestBlockHeightAttempt
} from "./ClientActions";
import { WALLETREMOVED_FAILED } from "./DaemonActions";
import { isTestNet, trezorDevice } from "selectors";
import { isTestNet, trezorDevice, ledgerDevice } from "selectors";
import { walletrpc as api } from "middleware/walletrpc/api_pb";
import { push as pushHistory } from "connected-react-router";
import { stopNotifcations } from "./NotificationActions";
Expand All @@ -28,6 +28,7 @@ import * as cfgConstants from "constants/config";
import { RESCAN_PROGRESS } from "./ControlActions";
import { stopAccountMixer } from "./AccountMixerActions";
import { TRZ_WALLET_CLOSED } from "actions/TrezorActions";
import { LDG_WALLET_CLOSED } from "actions/LedgerActions";
import { saveSettings, updateStateSettingsChanged } from "./SettingsActions";

const { SyncNotificationType } = api;
Expand Down Expand Up @@ -156,7 +157,7 @@ export const CREATEWATCHONLYWALLET_FAILED = "CREATEWATCHONLYWALLET_FAILED";
export const CREATEWATCHONLYWALLET_SUCCESS = "CREATEWATCHONLYWALLET_SUCCESS";

export const createWatchOnlyWalletRequest =
(extendedPubKey, pubPass = "") =>
(extendedPubKey, isLedger, isTrezor, pubPass = "") =>
(dispatch, getState) =>
new Promise((resolve, reject) => {
dispatch({ type: CREATEWATCHONLYWALLET_ATTEMPT });
Expand All @@ -172,6 +173,12 @@ export const createWatchOnlyWalletRequest =
} = getState();
const config = wallet.getWalletCfg(isTestNet(getState()), walletName);
config.set(cfgConstants.IS_WATCH_ONLY, true);
if (isTrezor) {
config.set(cfgConstants.TREZOR, true);
}
if (isLedger) {
config.set(cfgConstants.LEDGER, true);
}
config.delete(cfgConstants.DISCOVER_ACCOUNTS);
wallet.setIsWatchingOnly(true);
dispatch({ response: {}, type: CREATEWATCHONLYWALLET_SUCCESS });
Expand Down Expand Up @@ -269,6 +276,7 @@ const finalCloseWallet = () => async (dispatch, getState) => {
await wallet.stopWallet();
dispatch({ type: CLOSEWALLET_SUCCESS });
if (trezorDevice(getState())) dispatch({ type: TRZ_WALLET_CLOSED });
if (ledgerDevice(getState())) dispatch({ type: LDG_WALLET_CLOSED });
dispatch(pushHistory("/getstarted/initial"));
} catch (error) {
dispatch({ error, type: CLOSEWALLET_FAILED });
Expand Down
2 changes: 2 additions & 0 deletions app/components/SideBar/MenuLinks/Links.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const LN_KEY = "ln";
export const DEX_KEY = "dex";
export const TICKETS_KEY = "tickets";
export const GOV_KEY = "governance";
export const PRIV_KEY = "privacy";

export const linkList = [
{
Expand Down Expand Up @@ -48,6 +49,7 @@ export const linkList = [
path: "/privacy",
link: <T id="sidebar.link.privacy" m="Privacy and Security" />,
icon: "securitycntr",
key: PRIV_KEY,
ariaLabel: "Privacy"
},
{
Expand Down
17 changes: 14 additions & 3 deletions app/components/SideBar/MenuLinks/hooks.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { useEffect, useState, useMemo } from "react";
import { useSelector } from "react-redux";
import * as sel from "selectors";
import { linkList, LN_KEY, DEX_KEY, TICKETS_KEY, GOV_KEY } from "./Links";
import {
linkList,
LN_KEY,
DEX_KEY,
TICKETS_KEY,
GOV_KEY,
PRIV_KEY
} from "./Links";
import { useHistory } from "react-router-dom";
import { cloneDeep } from "fp";

Expand All @@ -10,6 +17,7 @@ export function useMenuLinks() {
const sidebarOnBottom = useSelector(sel.sidebarOnBottom);
const expandSideBar = useSelector(sel.expandSideBar);
const isTrezor = useSelector(sel.isTrezor);
const isLedger = useSelector(sel.isLedger);
const lnEnabled = useSelector(sel.lnEnabled);

const newActiveVoteProposalsCount = useSelector(
Expand Down Expand Up @@ -47,19 +55,22 @@ export function useMenuLinks() {
links = links.filter((l) => l.key !== LN_KEY);
}
// TODO: Enable ticket purchacing for Trezor.
if (isTrezor) {
if (isTrezor || isLedger) {
links = links.filter(
(l) => l.key !== DEX_KEY && l.key !== TICKETS_KEY && l.key !== GOV_KEY
);
}
if (isLedger) {
links = links.filter((l) => l.key !== PRIV_KEY);
}
return links.map((link) => ({
...link,
notifProp: link.notifProp?.reduce(
(acc, np) => acc + (notifProps[np] || 0),
0
)
}));
}, [notifProps, isTrezor, lnEnabled]);
}, [notifProps, isTrezor, lnEnabled, isLedger]);

const [activeTabIndex, setActiveTabIndex] = useState(-1);
const history = useHistory();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ const SendTransactionButton = ({
unsignedTransaction,
isSendingTransaction,
isTrezor,
isLedger,
onAttemptSignTransaction,
onAttemptSignTransactionTrezor
onAttemptSignTransactionTrezor,
onAttemptSignTransactionLedger
} = useSendTransactionButton();

const signTransaction = (privpass) => {
Expand All @@ -31,6 +33,12 @@ const SendTransactionButton = ({
onSubmit?.();
};

const signTransactionLedger = () => {
if (disabled) return;
onAttemptSignTransactionLedger?.(unsignedTransaction);
onSubmit?.();
};

if (isTrezor) {
return (
<KeyBlueButton
Expand All @@ -40,6 +48,15 @@ const SendTransactionButton = ({
{buttonLabel ? buttonLabel : <T id="send.sendBtn" m="Send" />}
</KeyBlueButton>
);
} else if (isLedger) {
return (
<KeyBlueButton
onClick={signTransactionLedger}
disabled={disabled || isSendingTransaction}
loading={isSendingTransaction}>
{buttonLabel ? buttonLabel : <T id="send.sendBtn" m="Send" />}
</KeyBlueButton>
);
} else {
return (
<PassphraseModalButton
Expand Down
8 changes: 7 additions & 1 deletion app/components/buttons/SendTransactionButton/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,32 @@ import { useDispatch, useSelector } from "react-redux";
import * as sel from "selectors";
import * as ca from "actions/ControlActions";
import * as tza from "actions/TrezorActions";
import * as ldgr from "actions/LedgerActions";

export function useSendTransactionButton() {
const unsignedTransaction = useSelector(sel.unsignedTransaction);
const constructTxResponse = useSelector(sel.constructTxResponse);
const isSendingTransaction = useSelector(sel.isSendingTransaction);
const isTrezor = useSelector(sel.isTrezor);
const isLedger = useSelector(sel.isLedger);

const dispatch = useDispatch();
const onAttemptSignTransaction = (passphrase, rawTx, acct) => {
dispatch(ca.signTransactionAttempt(passphrase, rawTx, acct));
};
const onAttemptSignTransactionTrezor = (rawUnsigTx, constructTxResponse) =>
dispatch(tza.signTransactionAttemptTrezor(rawUnsigTx, constructTxResponse));
const onAttemptSignTransactionLedger = (rawUnsigTx) =>
dispatch(ldgr.signTransactionAttemptLedger(rawUnsigTx));

return {
unsignedTransaction,
constructTxResponse,
isSendingTransaction,
isTrezor,
isLedger,
onAttemptSignTransaction,
onAttemptSignTransactionTrezor
onAttemptSignTransactionTrezor,
onAttemptSignTransactionLedger
};
}
7 changes: 5 additions & 2 deletions app/components/shared/SendTransaction/Form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const Form = ({
unsignedRawTx,
isWatchingOnly,
isTrezor,
isLedger,
insuficientFunds,
styles,
hideDetails,
Expand Down Expand Up @@ -71,7 +72,9 @@ const Form = ({
<T id="send.insuficient.funds" m="Insufficient funds" />
</div>
)}
{((isTrezor && isWatchingOnly) || !isWatchingOnly) &&
{((isTrezor && isWatchingOnly) ||
(isLedger && isWatchingOnly) ||
!isWatchingOnly) &&
(getRunningIndicator ? (
<Tooltip
contentClassName={styles.disabledTooltip}
Expand Down Expand Up @@ -144,7 +147,7 @@ const Form = ({
</div>
</div>
</div>
{unsignedRawTx && isWatchingOnly && !isTrezor && (
{unsignedRawTx && isWatchingOnly && !isTrezor && !isLedger && (
<UnsignedTx
title={<T id="send.unsignedRawTxTite" m="Unsigned Raw Transaction:" />}
tx={unsignedRawTx}
Expand Down
2 changes: 2 additions & 0 deletions app/components/shared/SendTransaction/SendTransaction.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const SendTransaction = ({
totalSpent,
notMixedAccounts,
isTrezor,
isLedger,
isWatchingOnly,
isConstructingTransaction,
attemptConstructTransaction,
Expand Down Expand Up @@ -394,6 +395,7 @@ const SendTransaction = ({
willEnter,
isWatchingOnly,
isTrezor,
isLedger,
insuficientFunds,
styles,
hideDetails,
Expand Down
2 changes: 2 additions & 0 deletions app/components/shared/SendTransaction/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function useSendTransaction() {
shallowEqual
);
const isTrezor = useSelector(sel.isTrezor);
const isLedger = useSelector(sel.isLedger);
const isWatchingOnly = useSelector(sel.isWatchingOnly);
const isConstructingTransaction = useSelector(sel.isConstructingTransaction);
const constructTxRequestAttempt = useSelector(sel.constructTxRequestAttempt);
Expand Down Expand Up @@ -61,6 +62,7 @@ export function useSendTransaction() {
totalSpent,
notMixedAccounts,
isTrezor,
isLedger,
isWatchingOnly,
isConstructingTransaction,
attemptConstructTransaction,
Expand Down
Loading