Skip to content
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
3 changes: 2 additions & 1 deletion packages/hw-wallets/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@enkryptcom/hw-wallets",
"version": "0.0.5",
"version": "0.0.9",
"description": "Hardware wallet manager for enkrypt",
"type": "module",
"main": "src/index.ts",
Expand Down Expand Up @@ -61,6 +61,7 @@
"@polkadot/types": "^16.1.1",
"@polkadot/util": "^13.5.1",
"@trezor/connect": "^9.5.5",
"@trezor/connect-web": "^9.5.5",
"@trezor/connect-webextension": "^9.5.5",
"@zondax/ledger-substrate": "^1.1.2",
"bitcoinjs-lib": "^6.1.7",
Expand Down
21 changes: 7 additions & 14 deletions packages/hw-wallets/src/trezor/bitcoin/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import TrezorConnect from "@trezor/connect-webextension";
import { getHDPath } from "@trezor/connect/lib/utils/pathUtils";
import { HWwalletCapabilities, NetworkNames } from "@enkryptcom/types";
import HDKey from "hdkey";
import { bufferToHex } from "@enkryptcom/utils";
import type { TrezorConnect } from "@trezor/connect-web";
import {
AddressResponse,
BitcoinSignMessage,
Expand All @@ -13,10 +13,11 @@ import {
SignTransactionRequest,
} from "../../types";
import { supportedPaths, TrezorNetworkConfigs } from "./configs";
import getTrezorConnect from "../trezorConnect";

class TrezorEthereum implements HWWalletProvider {
network: NetworkNames;

TrezorConnect: TrezorConnect;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add null checking for TrezorConnect instance

The TrezorConnect property is not initialized in the constructor and could cause runtime errors if other methods are called before init().

Consider adding null checks in methods that use this.TrezorConnect:

async getAddress(options: getAddressRequest): Promise<AddressResponse> {
+  if (!this.TrezorConnect) {
+    throw new Error("TrezorConnect not initialized. Call init() first.");
+  }
  if (!supportedPaths[this.network])
    return Promise.reject(new Error("trezor-bitcoin: Invalid network name"));

Apply similar checks to signPersonalMessage and signTransaction methods.

Also applies to: 29-30

🤖 Prompt for AI Agents
In packages/hw-wallets/src/trezor/bitcoin/index.ts around lines 20 and 29-30,
the TrezorConnect property is declared but not initialized in the constructor,
which can cause runtime errors if methods like signPersonalMessage and
signTransaction are called before init(). To fix this, add null or undefined
checks for this.TrezorConnect at the start of these methods and handle the case
where it is not initialized, such as throwing an error or returning early, to
prevent runtime exceptions.

HDNodes: Record<string, HDKey>;

constructor(network: NetworkNames) {
Expand All @@ -25,15 +26,7 @@ class TrezorEthereum implements HWWalletProvider {
}

async init(): Promise<boolean> {
TrezorConnect.init({
manifest: {
email: "info@enkrypt.com",
appUrl: "https://www.enkrypt.com",
},
transports: ["BridgeTransport", "WebUsbTransport"],
connectSrc: "https://connect.trezor.io/9/",
_extendWebextensionLifetime: true,
});
this.TrezorConnect = await getTrezorConnect();
return true;
}

Expand All @@ -42,7 +35,7 @@ class TrezorEthereum implements HWWalletProvider {
return Promise.reject(new Error("trezor-bitcoin: Invalid network name"));

if (!this.HDNodes[options.pathType.basePath]) {
const rootPub = await TrezorConnect.getPublicKey({
const rootPub = await this.TrezorConnect.getPublicKey({
path: options.pathType.basePath,
showOnTrezor: options.confirmAddress,
} as any);
Expand Down Expand Up @@ -82,7 +75,7 @@ class TrezorEthereum implements HWWalletProvider {
if (options.type === "bip322-simple") {
throw new Error("trezor-bitcoin: bip322 signing not supported");
}
const result = await TrezorConnect.signMessage({
const result = await this.TrezorConnect.signMessage({
path: options.pathType.path.replace(`{index}`, options.pathIndex),
message: options.message.toString("hex"),
hex: true,
Expand All @@ -97,7 +90,7 @@ class TrezorEthereum implements HWWalletProvider {
const addressN = getHDPath(
options.pathType.path.replace(`{index}`, options.pathIndex),
);
return TrezorConnect.signTransaction({
return this.TrezorConnect.signTransaction({
coin: TrezorNetworkConfigs[this.network].symbol,
inputs: transactionOptions.psbtTx.txInputs.map((tx) => ({
address_n: addressN,
Expand Down
31 changes: 12 additions & 19 deletions packages/hw-wallets/src/trezor/ethereum/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import TrezorConnect from "@trezor/connect-webextension";
import { HWwalletCapabilities, NetworkNames } from "@enkryptcom/types";
import HDKey from "hdkey";
import { bigIntToHex, bufferToHex, hexToBuffer } from "@enkryptcom/utils";
import { publicToAddress, toRpcSig } from "@ethereumjs/util";
import { FeeMarketEIP1559Transaction, LegacyTransaction } from "@ethereumjs/tx";
import type { TrezorConnect } from "@trezor/connect-web";
import {
AddressResponse,
getAddressRequest,
Expand All @@ -13,10 +13,11 @@ import {
SignTransactionRequest,
} from "../../types";
import { supportedPaths } from "./configs";
import getTrezorConnect from "../trezorConnect";

class TrezorEthereum implements HWWalletProvider {
network: NetworkNames;

TrezorConnect: TrezorConnect;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add initialization checks for TrezorConnect

Same issue as in the bitcoin implementation - the TrezorConnect property could be undefined if methods are called before init().

Add null checks consistently across all methods that use this.TrezorConnect:

async getAddress(options: getAddressRequest): Promise<AddressResponse> {
+  if (!this.TrezorConnect) {
+    throw new Error("TrezorConnect not initialized. Call init() first.");
+  }
  if (!supportedPaths[this.network])
    return Promise.reject(new Error("trezor-ethereum: Invalid network name"));

Also applies to: 29-30

🤖 Prompt for AI Agents
In packages/hw-wallets/src/trezor/ethereum/index.ts around lines 20 and 29-30,
the TrezorConnect property may be undefined if methods are called before init().
To fix this, add null or undefined checks for this.TrezorConnect at the start of
all methods that use it, and handle the case where it is not initialized, such
as throwing an error or returning early. This ensures safe usage and prevents
runtime errors.

HDNodes: Record<string, HDKey>;

constructor(network: NetworkNames) {
Expand All @@ -25,15 +26,7 @@ class TrezorEthereum implements HWWalletProvider {
}

async init(): Promise<boolean> {
TrezorConnect.init({
manifest: {
email: "info@enkrypt.com",
appUrl: "https://www.enkrypt.com",
},
transports: ["BridgeTransport", "WebUsbTransport"],
connectSrc: "https://connect.trezor.io/9/",
_extendWebextensionLifetime: true,
});
this.TrezorConnect = await getTrezorConnect();
return true;
}

Expand All @@ -42,14 +35,14 @@ class TrezorEthereum implements HWWalletProvider {
return Promise.reject(new Error("trezor-ethereum: Invalid network name"));

if (!this.HDNodes[options.pathType.basePath]) {
const rootPub = await TrezorConnect.ethereumGetPublicKey({
const rootPub = await this.TrezorConnect.ethereumGetPublicKey({
path: options.pathType.basePath,
showOnTrezor: options.confirmAddress,
});
if (!rootPub.payload) {
throw new Error("popup failed to open");
}
if (!rootPub.success) throw new Error(rootPub.payload.error as string);
if (!rootPub.success) throw new Error((rootPub.payload as any).error);

const hdKey = new HDKey();
hdKey.publicKey = Buffer.from(rootPub.payload.publicKey, "hex");
Expand Down Expand Up @@ -78,12 +71,12 @@ class TrezorEthereum implements HWWalletProvider {
}

async signPersonalMessage(options: SignMessageRequest): Promise<string> {
const result = await TrezorConnect.ethereumSignMessage({
const result = await this.TrezorConnect.ethereumSignMessage({
path: options.pathType.path.replace(`{index}`, options.pathIndex),
message: options.message.toString("hex"),
hex: true,
});
if (!result.success) throw new Error(result.payload.error as string);
if (!result.success) throw new Error((result.payload as any).error);
return bufferToHex(hexToBuffer(result.payload.signature));
}

Expand All @@ -100,14 +93,14 @@ class TrezorEthereum implements HWWalletProvider {
data: bufferToHex(tx.data),
};
if ((options.transaction as LegacyTransaction).gasPrice) {
return TrezorConnect.ethereumSignTransaction({
return this.TrezorConnect.ethereumSignTransaction({
path: options.pathType.path.replace(`{index}`, options.pathIndex),
transaction: {
...txObject,
gasPrice: bigIntToHex(tx.gasPrice),
},
}).then((result) => {
if (!result.success) throw new Error(result.payload.error as string);
if (!result.success) throw new Error((result.payload as any).error);
const rv = BigInt(parseInt(result.payload.v, 16));
const cv = tx.common.chainId() * 2n + 35n;
return toRpcSig(
Expand All @@ -119,15 +112,15 @@ class TrezorEthereum implements HWWalletProvider {
}

tx = options.transaction as FeeMarketEIP1559Transaction;
return TrezorConnect.ethereumSignTransaction({
return this.TrezorConnect.ethereumSignTransaction({
path: options.pathType.path.replace(`{index}`, options.pathIndex),
transaction: {
...txObject,
maxFeePerGas: bigIntToHex(tx.maxFeePerGas),
maxPriorityFeePerGas: bigIntToHex(tx.maxPriorityFeePerGas),
},
}).then((result) => {
if (!result.success) throw new Error(result.payload.error as string);
if (!result.success) throw new Error((result.payload as any).error);
return toRpcSig(
BigInt(result.payload.v),
hexToBuffer(result.payload.r),
Expand Down
25 changes: 9 additions & 16 deletions packages/hw-wallets/src/trezor/solana/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import TrezorConnect from "@trezor/connect-webextension";
import type { TrezorConnect } from "@trezor/connect-web";
import { HWwalletCapabilities, NetworkNames } from "@enkryptcom/types";
import HDKey from "hdkey";
import base58 from "bs58";
Expand All @@ -12,10 +12,11 @@ import {
SolSignTransaction,
} from "../../types";
import { supportedPaths } from "./configs";
import getTrezorConnect from "../trezorConnect";

class TrezorSolana implements HWWalletProvider {
network: NetworkNames;

TrezorConnect: TrezorConnect;
HDNodes: Record<string, HDKey>;

constructor(network: NetworkNames) {
Expand All @@ -24,28 +25,20 @@ class TrezorSolana implements HWWalletProvider {
}

async init(): Promise<boolean> {
TrezorConnect.init({
manifest: {
email: "info@enkrypt.com",
appUrl: "https://www.enkrypt.com",
},
transports: ["BridgeTransport", "WebUsbTransport"],
connectSrc: "https://connect.trezor.io/9/",
_extendWebextensionLifetime: true,
});
this.TrezorConnect = await getTrezorConnect();
return true;
}

async getAddress(options: getAddressRequest): Promise<AddressResponse> {
if (!supportedPaths[this.network])
return Promise.reject(new Error("trezor-bitcoin: Invalid network name"));
const res = await TrezorConnect.solanaGetAddress({
const res = await this.TrezorConnect.solanaGetAddress({
path: options.pathType.path.replace(`{index}`, options.pathIndex),
showOnTrezor: options.confirmAddress,
});
return {
address: bufferToHex(base58.decode(res.payload.address)),
publicKey: bufferToHex(base58.decode(res.payload.address)),
address: bufferToHex(base58.decode((res.payload as any).address)),
publicKey: bufferToHex(base58.decode((res.payload as any).address)),
};
}

Expand All @@ -66,12 +59,12 @@ class TrezorSolana implements HWWalletProvider {
}

async signTransaction(options: SignTransactionRequest): Promise<string> {
return TrezorConnect.solanaSignTransaction({
return this.TrezorConnect.solanaSignTransaction({
path: options.pathType.path.replace(`{index}`, options.pathIndex),
serializedTx: (options.transaction as SolSignTransaction).solTx.toString(
"hex",
),
}).then((result) => result.payload.signature);
}).then((result) => (result.payload as any).signature);
}

static getSupportedNetworks(): NetworkNames[] {
Expand Down
29 changes: 29 additions & 0 deletions packages/hw-wallets/src/trezor/trezorConnect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { TrezorConnect as TrezorConnectType } from "@trezor/connect-web";

const getTrezorConnect = async () => {
if (chrome && chrome.runtime && chrome.runtime.getPlatformInfo) {
const TrezorConnect = await import("@trezor/connect-webextension");
await TrezorConnect.default.init({
manifest: {
email: "info@enkrypt.com",
appUrl: "https://www.enkrypt.com",
},
transports: ["BridgeTransport", "WebUsbTransport"],
connectSrc: "https://connect.trezor.io/9/",
_extendWebextensionLifetime: true,
});
return TrezorConnect.default as TrezorConnectType;
} else {
const TrezorConnect = await import("@trezor/connect-web");
await TrezorConnect.default.init({
lazyLoad: true,
manifest: {
email: "info@enkrypt.com",
appUrl: "http://www.myetherwallet.com",
},
});
return TrezorConnect.default as TrezorConnectType;
}
};

export default getTrezorConnect;
Loading
Loading