Skip to content

Commit

Permalink
refactor: lazy load HWW dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Nov 1, 2024
1 parent 25ef9d9 commit 33461d8
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 14 deletions.
31 changes: 31 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default [
{
ignores: [
"dist",
"regtest",
"coverage",
"node_modules",
"dnssec-prover",
Expand All @@ -27,4 +28,34 @@ export default [
"no-async-promise-executor": "off",
},
},
{
rules: {
"no-restricted-imports": [
"error",
{
patterns: [
{
message: "It is supposed to be lazy loaded",
group: ["*/lazy/**"],
},
{
message: "It is a heavy dependency",
group: [
"@trezor/connect-web",
"@ledgerhq/hw-app-eth",
"@ledgerhq/hw-transport",
"@ledgerhq/hw-transport-webhid",
],
},
],
},
],
},
},
{
files: ["*/lazy/**", "*/utils/hardware/*"],
rules: {
"no-restricted-imports": "off",
},
},
];
21 changes: 21 additions & 0 deletions src/lazy/Loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import log from "loglevel";

class Loader<T> {
private modules?: T;

constructor(
private readonly name: string,
private readonly initializer: () => Promise<T>,
) {}

public get = async (): Promise<T> => {
if (this.modules === undefined) {
log.info(`Loading ${this.name} modules`);
this.modules = await this.initializer();
}

return this.modules;
};
}

export default Loader;
37 changes: 29 additions & 8 deletions src/utils/hardware/LedgerSigner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Eth from "@ledgerhq/hw-app-eth";
import Transport from "@ledgerhq/hw-transport";
import TransportWebHID from "@ledgerhq/hw-transport-webhid";
import type Eth from "@ledgerhq/hw-app-eth";
import type Transport from "@ledgerhq/hw-transport";
import type TransportWebHID from "@ledgerhq/hw-transport-webhid";
import {
JsonRpcProvider,
Signature,
Expand All @@ -13,15 +13,20 @@ import log from "loglevel";
import { config } from "../../config";
import { EIP1193Provider } from "../../consts/Types";
import type { DictKey } from "../../i18n/i18n";
import Loader from "../../lazy/Loader";
import { HardwareSigner, derivationPaths } from "./HadwareSigner";

class LedgerSigner implements EIP1193Provider, HardwareSigner {
private static readonly supportedApps = ["Ethereum", "RSK", "RSK Test"];

private readonly provider: JsonRpcProvider;
private derivationPath = derivationPaths.Ethereum;
private readonly modules: Loader<{
eth: typeof Eth;
webhid: typeof TransportWebHID;
}>;

private transport?: Transport;
private derivationPath = derivationPaths.Ethereum;

constructor(
private readonly t: (
Expand All @@ -32,6 +37,18 @@ class LedgerSigner implements EIP1193Provider, HardwareSigner {
this.provider = new JsonRpcProvider(
config.assets["RBTC"]?.network?.rpcUrls[0],
);

this.modules = new Loader("Ledger", async () => {
const [eth, webhid] = await Promise.all([
import("@ledgerhq/hw-app-eth"),
import("@ledgerhq/hw-transport-webhid"),
]);

return {
eth: eth.default,
webhid: webhid.default,
};
});
}

public getDerivationPath = () => {
Expand All @@ -50,8 +67,10 @@ class LedgerSigner implements EIP1193Provider, HardwareSigner {
case "eth_requestAccounts": {
log.debug("Getting Ledger accounts");

const modules = await this.modules.get();

if (this.transport === undefined) {
this.transport = await TransportWebHID.create();
this.transport = await modules.webhid.create();
}

const openApp = (await this.getApp()).name;
Expand All @@ -63,7 +82,7 @@ class LedgerSigner implements EIP1193Provider, HardwareSigner {
throw this.t("ledger_open_app_prompt");
}

const eth = new Eth(this.transport);
const eth = new modules.eth(this.transport);
const { address } = await eth.getAddress(this.derivationPath);

return [address.toLowerCase()];
Expand All @@ -90,7 +109,8 @@ class LedgerSigner implements EIP1193Provider, HardwareSigner {
gasLimit: (txParams as unknown as { gas: number }).gas,
});

const eth = new Eth(this.transport);
const modules = await this.modules.get();
const eth = new modules.eth(this.transport);
const signature = await eth.clearSignTransaction(
this.derivationPath,
tx.unsignedSerialized.substring(2),
Expand All @@ -108,7 +128,8 @@ class LedgerSigner implements EIP1193Provider, HardwareSigner {
case "eth_signTypedData_v4": {
log.debug("Signing EIP-712 message with Ledger");

const eth = new Eth(this.transport);
const modules = await this.modules.get();
const eth = new modules.eth(this.transport);
const message = JSON.parse(request.params[1] as string);

try {
Expand Down
22 changes: 16 additions & 6 deletions src/utils/hardware/TrezorSigner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Address, Unsuccessful } from "@trezor/connect-web";
import TrezorConnect from "@trezor/connect-web";
import type TrezorConnect from "@trezor/connect-web";
import type {
Response,
SuccessWithDevice,
Expand All @@ -15,12 +15,14 @@ import log from "loglevel";

import { config } from "../../config";
import { EIP1193Provider } from "../../consts/Types";
import Loader from "../../lazy/Loader";
import { HardwareSigner, derivationPaths } from "./HadwareSigner";

/* eslint-disable @typescript-eslint/no-explicit-any */

class TrezorSigner implements EIP1193Provider, HardwareSigner {
private readonly provider: JsonRpcProvider;
private readonly modules: Loader<typeof TrezorConnect>;

private initialized = false;
private derivationPath!: string;
Expand All @@ -30,6 +32,9 @@ class TrezorSigner implements EIP1193Provider, HardwareSigner {
config.assets["RBTC"]?.network?.rpcUrls[0],
);
this.setDerivationPath(derivationPaths.Ethereum);
this.modules = new Loader("Trezor", async () => {
return (await import("@trezor/connect-web")).default;
});
}

public getDerivationPath = () => {
Expand All @@ -50,8 +55,9 @@ class TrezorSigner implements EIP1193Provider, HardwareSigner {

await this.initialize();

const connect = await this.modules.get();
const addresses = this.handleError<Address>(
await TrezorConnect.ethereumGetAddress({
await connect.ethereumGetAddress({
showOnTrezor: false,
path: this.derivationPath,
} as any),
Expand All @@ -67,7 +73,8 @@ class TrezorSigner implements EIP1193Provider, HardwareSigner {

const txParams = request.params[0] as TransactionLike;

const [nonce, network, feeData] = await Promise.all([
const [connect, nonce, network, feeData] = await Promise.all([
this.modules.get(),
this.provider.getTransactionCount(txParams.from),
this.provider.getNetwork(),
this.provider.getFeeData(),
Expand All @@ -82,8 +89,9 @@ class TrezorSigner implements EIP1193Provider, HardwareSigner {
gasPrice: feeData.gasPrice.toString(16),
value: BigInt(txParams.value || 0).toString(16),
};

const signature = this.handleError(
await TrezorConnect.ethereumSignTransaction({
await connect.ethereumSignTransaction({
transaction: trezorTx,
path: this.derivationPath,
} as unknown as any),
Expand Down Expand Up @@ -116,8 +124,9 @@ class TrezorSigner implements EIP1193Provider, HardwareSigner {
};
delete types["EIP712Domain"];

const connect = await this.modules.get();
const signature = this.handleError(
await TrezorConnect.ethereumSignTypedData({
await connect.ethereumSignTypedData({
data: message,
metamask_v4_compat: true,
path: this.derivationPath,
Expand Down Expand Up @@ -148,7 +157,8 @@ class TrezorSigner implements EIP1193Provider, HardwareSigner {
}

try {
await TrezorConnect.init({
const connect = await this.modules.get();
await connect.init({
lazyLoad: true,
manifest: {
email: "[email protected]",
Expand Down

0 comments on commit 33461d8

Please sign in to comment.