Skip to content

Commit c97263d

Browse files
authored
Add verify ledger address button (#295)
1 parent 4265a89 commit c97263d

File tree

8 files changed

+266
-25
lines changed

8 files changed

+266
-25
lines changed

main/api/ledger/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,7 @@ export const ledgerRouter = t.router({
137137
.mutation(async (opts) => {
138138
return handleCreateSigningPackage(opts.input);
139139
}),
140+
verifyAddress: t.procedure.mutation(async () => {
141+
return ledgerManager.verifyPublicAddress();
142+
}),
140143
});

main/api/ledger/utils/ledgerManager.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,29 @@ class LedgerManager {
215215
cancelTransaction() {
216216
this.signTransactionPromise = null;
217217
}
218+
219+
verifyPublicAddress = async () => {
220+
try {
221+
const publicAddress = await this.ledgerSingleSigner.getPublicAddress({
222+
showInDevice: true,
223+
});
224+
225+
return publicAddress;
226+
} catch (err) {
227+
if (err instanceof LedgerActionRejected) {
228+
throw new Error("TRANSACTION_REJECTED");
229+
}
230+
231+
if (
232+
err instanceof LedgerAppNotOpen ||
233+
err instanceof LedgerDeviceLockedError
234+
) {
235+
throw new Error("APP_NOT_OPEN");
236+
}
237+
238+
throw new Error("Something went wrong, please try again");
239+
}
240+
};
218241
}
219242

220243
export const ledgerManager = new LedgerManager();

main/api/ledger/utils/ledgerSingleSigner.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@ export class LedgerSingleSigner extends Ledger {
2020
super(false);
2121
}
2222

23-
getPublicAddress = async () => {
23+
getPublicAddress = async ({
24+
showInDevice,
25+
}: {
26+
showInDevice?: boolean;
27+
} = {}) => {
2428
const response: KeyResponse = await this.tryInstruction((app) =>
25-
app.retrieveKeys(this.PATH, IronfishKeys.PublicAddress, false),
29+
app.retrieveKeys(this.PATH, IronfishKeys.PublicAddress, !!showInDevice),
2630
);
2731

2832
if (!isResponseAddress(response)) {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { Box, Code, HStack, Spinner, Text, VStack } from "@chakra-ui/react";
2+
import { defineMessages, useIntl } from "react-intl";
3+
4+
import { trpcReact } from "@/providers/TRPCProvider";
5+
import { COLORS } from "@/ui/colors";
6+
import { PillButton } from "@/ui/PillButton/PillButton";
7+
8+
const messages = defineMessages({
9+
appNotOpen: {
10+
defaultMessage:
11+
"Your Ledger device is locked or the Ironfish app is not open.",
12+
},
13+
transactionRejected: {
14+
defaultMessage: "The request was rejected on your Ledger device.",
15+
},
16+
viewAddressInstructions: {
17+
defaultMessage:
18+
"View the public address of your connected Ledger device by clicking the button below.",
19+
},
20+
deviceDisplayInstructions: {
21+
defaultMessage:
22+
"Your device will display its public address, and if you approve the request we will also display the address below.",
23+
},
24+
devicePrerequisites: {
25+
defaultMessage:
26+
"Ensure that your Ledger device is unlocked and that the Ironfish app is open before proceeding.",
27+
},
28+
approveRequest: {
29+
defaultMessage: "Please approve the request on your Ledger device.",
30+
},
31+
addressLabel: {
32+
defaultMessage: "Address:",
33+
},
34+
viewAddressButton: {
35+
defaultMessage: "View Address",
36+
},
37+
genericError: {
38+
defaultMessage: "Something went wrong, please try again.",
39+
},
40+
});
41+
42+
function getErrorMessage(error: string) {
43+
if (error === "APP_NOT_OPEN") {
44+
return messages.appNotOpen;
45+
}
46+
47+
if (error === "TRANSACTION_REJECTED") {
48+
return messages.transactionRejected;
49+
}
50+
51+
return messages.genericError;
52+
}
53+
54+
export function ViewLedgerAddress() {
55+
const { formatMessage } = useIntl();
56+
const { mutate, isLoading, data, error, isSuccess, isError } =
57+
trpcReact.verifyAddress.useMutation();
58+
59+
return (
60+
<Box>
61+
<VStack alignItems="stretch">
62+
<Text>{formatMessage(messages.viewAddressInstructions)}</Text>
63+
64+
<Text>{formatMessage(messages.deviceDisplayInstructions)}</Text>
65+
66+
<Text>{formatMessage(messages.devicePrerequisites)}</Text>
67+
</VStack>
68+
69+
<Box my={6}>
70+
{(isSuccess || isLoading) && (
71+
<VStack
72+
p={8}
73+
borderRadius={4}
74+
bg={COLORS.GRAY_LIGHT}
75+
alignItems="stretch"
76+
gap={4}
77+
_dark={{
78+
bg: "transparent",
79+
border: `1px solid ${COLORS.DARK_MODE.GRAY_MEDIUM}`,
80+
}}
81+
>
82+
{isLoading ? (
83+
<VStack justifyContent="center" my={4} gap={4}>
84+
<Spinner opacity="0.5" size="lg" />
85+
<Text>{formatMessage(messages.approveRequest)}</Text>
86+
</VStack>
87+
) : (
88+
<VStack alignItems="stretch">
89+
<Text fontWeight="bold">
90+
{formatMessage(messages.addressLabel)}
91+
</Text>
92+
<Text>{data}</Text>
93+
</VStack>
94+
)}
95+
</VStack>
96+
)}
97+
98+
{isError && (
99+
<Code
100+
colorScheme="red"
101+
p={4}
102+
maxH="400px"
103+
maxW="100%"
104+
w="100%"
105+
overflow="auto"
106+
mb={6}
107+
>
108+
<Text as="pre">
109+
{formatMessage(getErrorMessage(error.message))}
110+
</Text>
111+
</Code>
112+
)}
113+
</Box>
114+
115+
<HStack>
116+
<PillButton isDisabled={isLoading} onClick={() => mutate()}>
117+
{formatMessage(messages.viewAddressButton)}
118+
</PillButton>
119+
</HStack>
120+
</Box>
121+
);
122+
}

renderer/intl/locales/en-US.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
"+RhnH+": {
66
"message": "Empty"
77
},
8+
"+VatSc": {
9+
"message": "Ensure that your Ledger device is unlocked and that the Ironfish app is open before proceeding."
10+
},
811
"+gH1Ai": {
912
"message": "Node Name"
1013
},
@@ -427,6 +430,9 @@
427430
"NX/nQR": {
428431
"message": "Changing node settings can optimize performance, improve connectivity, enhance security, and manage resources effectively."
429432
},
433+
"NXKaWE": {
434+
"message": "The request was rejected on your Ledger device."
435+
},
430436
"NZYRdf": {
431437
"message": "Mainnet"
432438
},
@@ -460,6 +466,9 @@
460466
"PLUyno": {
461467
"message": "Switch between light and dark mode."
462468
},
469+
"POEtw2": {
470+
"message": "Utilities for interacting with your Ledger device."
471+
},
463472
"Pe0ogR": {
464473
"message": "Theme"
465474
},
@@ -733,6 +742,9 @@
733742
"iWiHY7": {
734743
"message": "The blockchain is syncing. Your balance may be inaccurate and sending transactions will be disabled until the sync is complete."
735744
},
745+
"iqo0HR": {
746+
"message": "View Address"
747+
},
736748
"is+QTN": {
737749
"message": "Contact Settings"
738750
},
@@ -769,6 +781,12 @@
769781
"kTt/ND": {
770782
"message": "Russian"
771783
},
784+
"klgjDZ": {
785+
"message": "View the public address of your connected Ledger device by clicking the button below."
786+
},
787+
"koRMZ3": {
788+
"message": "Address:"
789+
},
772790
"krty63": {
773791
"message": "Need help?"
774792
},
@@ -856,6 +874,9 @@
856874
"rGIQdX": {
857875
"message": "Back to Account Overview"
858876
},
877+
"rKs+bp": {
878+
"message": "Please approve the request on your Ledger device."
879+
},
859880
"rbrahO": {
860881
"message": "Close"
861882
},
@@ -868,6 +889,9 @@
868889
"sXlL42": {
869890
"message": "Encrypted Wallets Unsupported"
870891
},
892+
"scwekL": {
893+
"message": "Ledger"
894+
},
871895
"tBX0Dj": {
872896
"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."
873897
},
@@ -886,6 +910,9 @@
886910
"tjHKMS": {
887911
"message": "Sender Address"
888912
},
913+
"trO2pQ": {
914+
"message": "Your Ledger device is locked or the Ironfish app is not open."
915+
},
889916
"tzMNF3": {
890917
"message": "Status"
891918
},
@@ -922,6 +949,9 @@
922949
"wsALI4": {
923950
"message": "Enter Encoded Key"
924951
},
952+
"x5CZLw": {
953+
"message": "Your device will display its public address, and if you approve the request we will also display the address below."
954+
},
925955
"xP64Lw": {
926956
"message": "Address Book"
927957
},
@@ -970,6 +1000,9 @@
9701000
"zFegDD": {
9711001
"message": "Contact"
9721002
},
1003+
"zHNkbi": {
1004+
"message": "View your public address on your Ledger device."
1005+
},
9731006
"zR2zr+": {
9741007
"message": "Address copied to clipboard"
9751008
},

renderer/layouts/MainLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ function Sidebar() {
214214
type Props = {
215215
children: ReactNode;
216216
backLinkProps?: {
217-
label: string;
217+
label: string | null;
218218
href: string;
219219
};
220220
};

0 commit comments

Comments
 (0)