Skip to content

Commit

Permalink
Add verify ledger address button (#295)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgca authored Dec 9, 2024
1 parent 4265a89 commit c97263d
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 25 deletions.
3 changes: 3 additions & 0 deletions main/api/ledger/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,7 @@ export const ledgerRouter = t.router({
.mutation(async (opts) => {
return handleCreateSigningPackage(opts.input);
}),
verifyAddress: t.procedure.mutation(async () => {
return ledgerManager.verifyPublicAddress();
}),
});
23 changes: 23 additions & 0 deletions main/api/ledger/utils/ledgerManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,29 @@ class LedgerManager {
cancelTransaction() {
this.signTransactionPromise = null;
}

verifyPublicAddress = async () => {
try {
const publicAddress = await this.ledgerSingleSigner.getPublicAddress({
showInDevice: true,
});

return publicAddress;
} catch (err) {
if (err instanceof LedgerActionRejected) {
throw new Error("TRANSACTION_REJECTED");
}

if (
err instanceof LedgerAppNotOpen ||
err instanceof LedgerDeviceLockedError
) {
throw new Error("APP_NOT_OPEN");
}

throw new Error("Something went wrong, please try again");
}
};
}

export const ledgerManager = new LedgerManager();
8 changes: 6 additions & 2 deletions main/api/ledger/utils/ledgerSingleSigner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ export class LedgerSingleSigner extends Ledger {
super(false);
}

getPublicAddress = async () => {
getPublicAddress = async ({
showInDevice,
}: {
showInDevice?: boolean;
} = {}) => {
const response: KeyResponse = await this.tryInstruction((app) =>
app.retrieveKeys(this.PATH, IronfishKeys.PublicAddress, false),
app.retrieveKeys(this.PATH, IronfishKeys.PublicAddress, !!showInDevice),
);

if (!isResponseAddress(response)) {
Expand Down
122 changes: 122 additions & 0 deletions renderer/components/ViewLedgerAddress/ViewLedgerAddress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Box, Code, HStack, Spinner, Text, VStack } from "@chakra-ui/react";
import { defineMessages, useIntl } from "react-intl";

import { trpcReact } from "@/providers/TRPCProvider";
import { COLORS } from "@/ui/colors";
import { PillButton } from "@/ui/PillButton/PillButton";

const messages = defineMessages({
appNotOpen: {
defaultMessage:
"Your Ledger device is locked or the Ironfish app is not open.",
},
transactionRejected: {
defaultMessage: "The request was rejected on your Ledger device.",
},
viewAddressInstructions: {
defaultMessage:
"View the public address of your connected Ledger device by clicking the button below.",
},
deviceDisplayInstructions: {
defaultMessage:
"Your device will display its public address, and if you approve the request we will also display the address below.",
},
devicePrerequisites: {
defaultMessage:
"Ensure that your Ledger device is unlocked and that the Ironfish app is open before proceeding.",
},
approveRequest: {
defaultMessage: "Please approve the request on your Ledger device.",
},
addressLabel: {
defaultMessage: "Address:",
},
viewAddressButton: {
defaultMessage: "View Address",
},
genericError: {
defaultMessage: "Something went wrong, please try again.",
},
});

function getErrorMessage(error: string) {
if (error === "APP_NOT_OPEN") {
return messages.appNotOpen;
}

if (error === "TRANSACTION_REJECTED") {
return messages.transactionRejected;
}

return messages.genericError;
}

export function ViewLedgerAddress() {
const { formatMessage } = useIntl();
const { mutate, isLoading, data, error, isSuccess, isError } =
trpcReact.verifyAddress.useMutation();

return (
<Box>
<VStack alignItems="stretch">
<Text>{formatMessage(messages.viewAddressInstructions)}</Text>

<Text>{formatMessage(messages.deviceDisplayInstructions)}</Text>

<Text>{formatMessage(messages.devicePrerequisites)}</Text>
</VStack>

<Box my={6}>
{(isSuccess || isLoading) && (
<VStack
p={8}
borderRadius={4}
bg={COLORS.GRAY_LIGHT}
alignItems="stretch"
gap={4}
_dark={{
bg: "transparent",
border: `1px solid ${COLORS.DARK_MODE.GRAY_MEDIUM}`,
}}
>
{isLoading ? (
<VStack justifyContent="center" my={4} gap={4}>
<Spinner opacity="0.5" size="lg" />
<Text>{formatMessage(messages.approveRequest)}</Text>
</VStack>
) : (
<VStack alignItems="stretch">
<Text fontWeight="bold">
{formatMessage(messages.addressLabel)}
</Text>
<Text>{data}</Text>
</VStack>
)}
</VStack>
)}

{isError && (
<Code
colorScheme="red"
p={4}
maxH="400px"
maxW="100%"
w="100%"
overflow="auto"
mb={6}
>
<Text as="pre">
{formatMessage(getErrorMessage(error.message))}
</Text>
</Code>
)}
</Box>

<HStack>
<PillButton isDisabled={isLoading} onClick={() => mutate()}>
{formatMessage(messages.viewAddressButton)}
</PillButton>
</HStack>
</Box>
);
}
33 changes: 33 additions & 0 deletions renderer/intl/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"+RhnH+": {
"message": "Empty"
},
"+VatSc": {
"message": "Ensure that your Ledger device is unlocked and that the Ironfish app is open before proceeding."
},
"+gH1Ai": {
"message": "Node Name"
},
Expand Down Expand Up @@ -427,6 +430,9 @@
"NX/nQR": {
"message": "Changing node settings can optimize performance, improve connectivity, enhance security, and manage resources effectively."
},
"NXKaWE": {
"message": "The request was rejected on your Ledger device."
},
"NZYRdf": {
"message": "Mainnet"
},
Expand Down Expand Up @@ -460,6 +466,9 @@
"PLUyno": {
"message": "Switch between light and dark mode."
},
"POEtw2": {
"message": "Utilities for interacting with your Ledger device."
},
"Pe0ogR": {
"message": "Theme"
},
Expand Down Expand Up @@ -733,6 +742,9 @@
"iWiHY7": {
"message": "The blockchain is syncing. Your balance may be inaccurate and sending transactions will be disabled until the sync is complete."
},
"iqo0HR": {
"message": "View Address"
},
"is+QTN": {
"message": "Contact Settings"
},
Expand Down Expand Up @@ -769,6 +781,12 @@
"kTt/ND": {
"message": "Russian"
},
"klgjDZ": {
"message": "View the public address of your connected Ledger device by clicking the button below."
},
"koRMZ3": {
"message": "Address:"
},
"krty63": {
"message": "Need help?"
},
Expand Down Expand Up @@ -856,6 +874,9 @@
"rGIQdX": {
"message": "Back to Account Overview"
},
"rKs+bp": {
"message": "Please approve the request on your Ledger device."
},
"rbrahO": {
"message": "Close"
},
Expand All @@ -868,6 +889,9 @@
"sXlL42": {
"message": "Encrypted Wallets Unsupported"
},
"scwekL": {
"message": "Ledger"
},
"tBX0Dj": {
"message": "Your Iron Fish wallet is encrypted. Encrypted wallets are not yet supported in the node app. Please decrypt your wallet using the CLI to use the node app."
},
Expand All @@ -886,6 +910,9 @@
"tjHKMS": {
"message": "Sender Address"
},
"trO2pQ": {
"message": "Your Ledger device is locked or the Ironfish app is not open."
},
"tzMNF3": {
"message": "Status"
},
Expand Down Expand Up @@ -922,6 +949,9 @@
"wsALI4": {
"message": "Enter Encoded Key"
},
"x5CZLw": {
"message": "Your device will display its public address, and if you approve the request we will also display the address below."
},
"xP64Lw": {
"message": "Address Book"
},
Expand Down Expand Up @@ -970,6 +1000,9 @@
"zFegDD": {
"message": "Contact"
},
"zHNkbi": {
"message": "View your public address on your Ledger device."
},
"zR2zr+": {
"message": "Address copied to clipboard"
},
Expand Down
2 changes: 1 addition & 1 deletion renderer/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ function Sidebar() {
type Props = {
children: ReactNode;
backLinkProps?: {
label: string;
label: string | null;
href: string;
};
};
Expand Down
Loading

0 comments on commit c97263d

Please sign in to comment.