Skip to content

Commit caaeee7

Browse files
authored
Adds initial feature flagged Ledger UI (#220)
* Saving progress * Save: * Add ledger manager * Add initial modal UI * Add + icon to Add Account button
1 parent d962dde commit caaeee7

File tree

16 files changed

+597
-83
lines changed

16 files changed

+597
-83
lines changed

main/api/ledger/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ledgerManager } from "./utils/ledger";
2+
import { t } from "../trpc";
3+
4+
export const ledgerRouter = t.router({
5+
connectLedger: t.procedure.query(async () => {
6+
const app = await ledgerManager.connect();
7+
const appInfo = await app.appInfo();
8+
return appInfo.appVersion;
9+
}),
10+
getLedgerPublicAddress: t.procedure.query(async () => {
11+
const address = await ledgerManager.getPublicAddress();
12+
return address;
13+
}),
14+
});

main/api/ledger/utils/ledger.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import TransportNodeHid from "@ledgerhq/hw-transport-node-hid";
2+
import IronfishApp, { IronfishKeys } from "@zondax/ledger-ironfish";
3+
4+
import { logger } from "../../ironfish/logger";
5+
6+
export const DERIVATION_PATH = "m/44'/1338'/0";
7+
const OPEN_TIMEOUT = 3000;
8+
const LISTEN_TIMEOUT = 3000;
9+
10+
let cachedApp: IronfishApp | null = null;
11+
12+
class LedgerManager {
13+
app: IronfishApp | null = null;
14+
DERIVATION_PATH = DERIVATION_PATH;
15+
16+
connect = async () => {
17+
if (cachedApp) {
18+
return cachedApp;
19+
}
20+
21+
const transport = await TransportNodeHid.create(
22+
OPEN_TIMEOUT,
23+
LISTEN_TIMEOUT,
24+
);
25+
26+
const app = new IronfishApp(transport);
27+
28+
const appInfo = await app.appInfo();
29+
30+
const appName = appInfo.appName ?? "App name not found";
31+
logger.debug(appName);
32+
33+
if (appName !== "Ironfish") {
34+
logger.debug(appName);
35+
logger.debug(appInfo.returnCode.toString());
36+
logger.debug(appInfo.errorMessage.toString());
37+
throw new Error(
38+
"Invalid app name. Please open the Iron Fish app on your ledger device.",
39+
);
40+
}
41+
42+
if (appInfo.appVersion) {
43+
logger.debug(`Ironfish App Version: ${appInfo.appVersion}`);
44+
}
45+
46+
cachedApp = app;
47+
return app;
48+
};
49+
50+
disconnect = async () => {
51+
if (this.app) {
52+
await this.app.transport.close();
53+
this.app = null;
54+
}
55+
56+
return true;
57+
};
58+
59+
getPublicAddress = async () => {
60+
if (!this.app) {
61+
throw new Error("App not connected");
62+
}
63+
64+
const response = await this.app.retrieveKeys(
65+
DERIVATION_PATH,
66+
IronfishKeys.PublicAddress,
67+
false,
68+
);
69+
70+
const publicAddress =
71+
"publicAddress" in response ? response.publicAddress : null;
72+
73+
if (!publicAddress) {
74+
logger.debug(`Failed to retrieve public address`);
75+
logger.debug(response.returnCode.toString());
76+
throw new Error(response.errorMessage);
77+
}
78+
79+
return publicAddress.toString("hex");
80+
};
81+
}
82+
83+
export const ledgerManager = new LedgerManager();

package-lock.json

Lines changed: 183 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@ethersproject/bignumber": "^5.7.0",
3838
"@formatjs/cli": "^6.2.4",
3939
"@hookform/resolvers": "^3.3.2",
40+
"@ledgerhq/hw-transport-node-hid": "^6.29.0",
4041
"@radix-ui/react-select": "^2.0.0",
4142
"@tanstack/react-query": "^4.35.7",
4243
"@trpc/client": "^10.38.5",
@@ -52,6 +53,7 @@
5253
"@types/uuid": "^9.0.5",
5354
"@typescript-eslint/eslint-plugin": "^6.7.4",
5455
"@typescript-eslint/parser": "^6.7.4",
56+
"@zondax/ledger-ironfish": "^0.1.1",
5557
"axios": "0.21.4",
5658
"babel-plugin-formatjs": "^10.5.10",
5759
"compare-versions": "6.1.0",

0 commit comments

Comments
 (0)