diff --git a/packages/signer/keyring-btc/package.json b/packages/signer/keyring-btc/package.json index fc8d4d299..ad6d1cf67 100644 --- a/packages/signer/keyring-btc/package.json +++ b/packages/signer/keyring-btc/package.json @@ -51,6 +51,7 @@ "@ledgerhq/eslint-config-dsdk": "workspace:*", "@ledgerhq/jest-config-dsdk": "workspace:*", "@ledgerhq/prettier-config-dsdk": "workspace:*", + "@ledgerhq/signer-utils": "workspace:*", "@ledgerhq/tsconfig-dsdk": "workspace:*", "ts-node": "^10.9.2" }, diff --git a/packages/signer/keyring-btc/src/internal/app-binder/command/GetExtendedPublicKeyCommand.ts b/packages/signer/keyring-btc/src/internal/app-binder/command/GetExtendedPublicKeyCommand.ts index 4132d367b..542f2dd38 100644 --- a/packages/signer/keyring-btc/src/internal/app-binder/command/GetExtendedPublicKeyCommand.ts +++ b/packages/signer/keyring-btc/src/internal/app-binder/command/GetExtendedPublicKeyCommand.ts @@ -12,8 +12,7 @@ import { GlobalCommandErrorHandler, InvalidStatusWordError, } from "@ledgerhq/device-management-kit"; - -import { DerivationPathUtils } from "@internal/shared/utils/DerivationPathUtils"; +import { DerivationPathUtils } from "@ledgerhq/signer-utils"; const STATUS_CODE_LENGTH = 2; diff --git a/packages/signer/keyring-btc/src/internal/shared/utils/DerivationPathUtils.test.ts b/packages/signer/keyring-btc/src/internal/shared/utils/DerivationPathUtils.test.ts deleted file mode 100644 index 41bfa246c..000000000 --- a/packages/signer/keyring-btc/src/internal/shared/utils/DerivationPathUtils.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { DerivationPathUtils } from "./DerivationPathUtils"; - -const PADDING = 0x80000000; - -describe("DerivationPathUtils", () => { - it("should split the derivation path", () => { - // GIVEN - const path = "44'/60/0/0/0"; - - // WHEN - const result = DerivationPathUtils.splitPath(path); - - // THEN - expect(result).toStrictEqual([44 + PADDING, 60, 0, 0, 0]); - }); - - it("should split the derivation path with hardened path", () => { - // GIVEN - const path = "44'/60'/0'/0'/1"; - - // WHEN - const result = DerivationPathUtils.splitPath(path); - - // THEN - expect(result).toStrictEqual([ - 44 + PADDING, - 60 + PADDING, - 0 + PADDING, - 0 + PADDING, - 1, - ]); - }); - - it("should split the derivation path with custom path", () => { - // GIVEN - const path = "44'/60'/5/4/3"; - - // WHEN - const result = DerivationPathUtils.splitPath(path); - - // THEN - expect(result).toStrictEqual([44 + PADDING, 60 + PADDING, 5, 4, 3]); - }); - - it("should throw an error if invalid number provided", () => { - // GIVEN - const path = "44'/60'/zzz/4/3"; - - // WHEN - const result = () => DerivationPathUtils.splitPath(path); - - // THEN - expect(result).toThrow(new Error("Invalid number provided")); - }); -}); diff --git a/packages/signer/keyring-btc/src/internal/shared/utils/DerivationPathUtils.ts b/packages/signer/keyring-btc/src/internal/shared/utils/DerivationPathUtils.ts deleted file mode 100644 index 5a8488049..000000000 --- a/packages/signer/keyring-btc/src/internal/shared/utils/DerivationPathUtils.ts +++ /dev/null @@ -1,21 +0,0 @@ -// TODO: Move to shared package and use in both keyring-btc and keyring-eth - -export class DerivationPathUtils { - private static readonly PADDING = 0x80000000; - - static splitPath(path: string): number[] { - const result: number[] = []; - const components = path.split("/"); - components.forEach((element) => { - let number = parseInt(element, 10); - if (isNaN(number)) { - throw new Error("Invalid number provided"); - } - if (element.length > 1 && element[element.length - 1] === "'") { - number += this.PADDING; - } - result.push(number); - }); - return result; - } -} diff --git a/packages/signer/keyring-eth/package.json b/packages/signer/keyring-eth/package.json index 86a954579..3f2a35ed9 100644 --- a/packages/signer/keyring-eth/package.json +++ b/packages/signer/keyring-eth/package.json @@ -51,6 +51,7 @@ "@ledgerhq/eslint-config-dsdk": "workspace:*", "@ledgerhq/jest-config-dsdk": "workspace:*", "@ledgerhq/prettier-config-dsdk": "workspace:*", + "@ledgerhq/signer-utils": "workspace:*", "@ledgerhq/tsconfig-dsdk": "workspace:*", "@types/semver": "^7.5.8", "rxjs": "^7.8.1", diff --git a/packages/signer/keyring-eth/src/internal/app-binder/command/GetAddressCommand.ts b/packages/signer/keyring-eth/src/internal/app-binder/command/GetAddressCommand.ts index 249d32145..6a3e2528f 100644 --- a/packages/signer/keyring-eth/src/internal/app-binder/command/GetAddressCommand.ts +++ b/packages/signer/keyring-eth/src/internal/app-binder/command/GetAddressCommand.ts @@ -12,12 +12,12 @@ import { InvalidStatusWordError, isHexaString, } from "@ledgerhq/device-management-kit"; +import { DerivationPathUtils } from "@ledgerhq/signer-utils"; import { GetAddressCommandArgs, GetAddressCommandResponse, } from "@api/app-binder/GetAddressCommandTypes"; -import { DerivationPathUtils } from "@internal/shared/utils/DerivationPathUtils"; const CHAIN_CODE_LENGTH = 32; diff --git a/packages/signer/keyring-eth/src/internal/app-binder/command/SignEIP712Command.ts b/packages/signer/keyring-eth/src/internal/app-binder/command/SignEIP712Command.ts index 4a982e742..3087c29f2 100644 --- a/packages/signer/keyring-eth/src/internal/app-binder/command/SignEIP712Command.ts +++ b/packages/signer/keyring-eth/src/internal/app-binder/command/SignEIP712Command.ts @@ -12,10 +12,10 @@ import { GlobalCommandErrorHandler, InvalidStatusWordError, } from "@ledgerhq/device-management-kit"; +import { DerivationPathUtils } from "@ledgerhq/signer-utils"; import { Maybe } from "purify-ts"; import { type Signature } from "@api/model/Signature"; -import { DerivationPathUtils } from "@internal/shared/utils/DerivationPathUtils"; const R_LENGTH = 32; const S_LENGTH = 32; diff --git a/packages/signer/keyring-eth/src/internal/app-binder/task/SendSignPersonalMessageTask.ts b/packages/signer/keyring-eth/src/internal/app-binder/task/SendSignPersonalMessageTask.ts index e98c42e18..b2238d9ae 100644 --- a/packages/signer/keyring-eth/src/internal/app-binder/task/SendSignPersonalMessageTask.ts +++ b/packages/signer/keyring-eth/src/internal/app-binder/task/SendSignPersonalMessageTask.ts @@ -6,13 +6,13 @@ import { InvalidStatusWordError, isSuccessCommandResult, } from "@ledgerhq/device-management-kit"; +import { DerivationPathUtils } from "@ledgerhq/signer-utils"; import { Signature } from "@api/model/Signature"; import { SignPersonalMessageCommand, SignPersonalMessageCommandResponse, } from "@internal/app-binder/command/SignPersonalMessageCommand"; -import { DerivationPathUtils } from "@internal/shared/utils/DerivationPathUtils"; import { SendCommandInChunksTask } from "./SendCommandInChunksTask"; diff --git a/packages/signer/keyring-eth/src/internal/app-binder/task/SendSignTransactionTask.ts b/packages/signer/keyring-eth/src/internal/app-binder/task/SendSignTransactionTask.ts index 0e8bcc1e5..a95ec579c 100644 --- a/packages/signer/keyring-eth/src/internal/app-binder/task/SendSignTransactionTask.ts +++ b/packages/signer/keyring-eth/src/internal/app-binder/task/SendSignTransactionTask.ts @@ -6,13 +6,13 @@ import { InvalidStatusWordError, isSuccessCommandResult, } from "@ledgerhq/device-management-kit"; +import { DerivationPathUtils } from "@ledgerhq/signer-utils"; import { Signature } from "@api/index"; import { SignTransactionCommand, SignTransactionCommandResponse, } from "@internal/app-binder/command/SignTransactionCommand"; -import { DerivationPathUtils } from "@internal/shared/utils/DerivationPathUtils"; import { SendCommandInChunksTask } from "./SendCommandInChunksTask"; diff --git a/packages/signer/signer-utils/.prettierignore b/packages/signer/signer-utils/.prettierignore new file mode 100644 index 000000000..af229265b --- /dev/null +++ b/packages/signer/signer-utils/.prettierignore @@ -0,0 +1,2 @@ +lib/* +coverage/* diff --git a/packages/signer/signer-utils/.prettierrc.js b/packages/signer/signer-utils/.prettierrc.js new file mode 100644 index 000000000..9601e1776 --- /dev/null +++ b/packages/signer/signer-utils/.prettierrc.js @@ -0,0 +1,3 @@ +module.exports = { + ...require("@ledgerhq/prettier-config-dsdk"), +}; diff --git a/packages/signer/signer-utils/CHANGELOG.md b/packages/signer/signer-utils/CHANGELOG.md new file mode 100644 index 000000000..fa01cbba2 --- /dev/null +++ b/packages/signer/signer-utils/CHANGELOG.md @@ -0,0 +1 @@ +# @ledgerhq/signer-utils diff --git a/packages/signer/signer-utils/README.md b/packages/signer/signer-utils/README.md new file mode 100644 index 000000000..b47bb86a5 --- /dev/null +++ b/packages/signer/signer-utils/README.md @@ -0,0 +1 @@ +# Ledger Signer Utils Package diff --git a/packages/signer/signer-utils/eslint.config.mjs b/packages/signer/signer-utils/eslint.config.mjs new file mode 100644 index 000000000..efdcd9509 --- /dev/null +++ b/packages/signer/signer-utils/eslint.config.mjs @@ -0,0 +1,13 @@ +import config from "@ledgerhq/eslint-config-dsdk"; + +export default [ + ...config, + { + ignores: ["eslint.config.mjs"], + languageOptions: { + parserOptions: { + project: "./tsconfig.json", + }, + }, + }, +]; diff --git a/packages/signer/signer-utils/jest.config.ts b/packages/signer/signer-utils/jest.config.ts new file mode 100644 index 000000000..c2216d42a --- /dev/null +++ b/packages/signer/signer-utils/jest.config.ts @@ -0,0 +1,26 @@ +/* eslint no-restricted-syntax: 0 */ +import { JestConfigWithTsJest, pathsToModuleNameMapper } from "ts-jest"; + +import { compilerOptions } from "./tsconfig.json"; + +const paths = pathsToModuleNameMapper(compilerOptions.paths, { + prefix: "/", +}); + +const config: JestConfigWithTsJest = { + preset: "@ledgerhq/jest-config-dsdk", + setupFiles: ["/jest.setup.ts"], + testPathIgnorePatterns: ["/lib/esm", "/lib/cjs"], + collectCoverageFrom: [ + "src/**/*.ts", + "!src/**/*.stub.ts", + "!src/index.ts", + "!src/api/index.ts", + "!src/**/__test-utils__/*", + ], + moduleNameMapper: { + ...paths, + }, +}; + +export default config; diff --git a/packages/signer/signer-utils/jest.setup.ts b/packages/signer/signer-utils/jest.setup.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/signer/signer-utils/package.json b/packages/signer/signer-utils/package.json new file mode 100644 index 000000000..4135a0d7f --- /dev/null +++ b/packages/signer/signer-utils/package.json @@ -0,0 +1,49 @@ +{ + "name": "@ledgerhq/signer-utils", + "version": "1.0.0", + "license": "Apache-2.0", + "private": true, + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "import": "./lib/esm/index.js", + "require": "./lib/cjs/index.js" + }, + "./*": { + "types": "./lib/types/*", + "import": "./lib/esm/*", + "require": "./lib/cjs/*" + } + }, + "files": [ + "./lib" + ], + "scripts": { + "prebuild": "rimraf lib", + "build": "pnpm lmdk-build --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json", + "dev": "concurrently \"pnpm watch:builds\" \"pnpm watch:types\"", + "watch:builds": "pnpm lmdk-watch --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json", + "watch:types": "concurrently \"tsc --watch -p tsconfig.prod.json\" \"tsc-alias --watch -p tsconfig.prod.json\"", + "lint": "eslint", + "lint:fix": "pnpm lint --fix", + "postpack": "find . -name '*.tgz' -exec cp {} ../../../dist/ \\; ", + "prettier": "prettier . --check", + "prettier:fix": "prettier . --write", + "typecheck": "tsc --noEmit", + "test": "jest", + "test:watch": "pnpm test -- --watch", + "test:coverage": "pnpm test -- --coverage" + }, + "devDependencies": { + "@ledgerhq/device-management-kit": "workspace:*", + "@ledgerhq/esbuild-tools": "workspace:*", + "@ledgerhq/eslint-config-dsdk": "workspace:*", + "@ledgerhq/jest-config-dsdk": "workspace:*", + "@ledgerhq/prettier-config-dsdk": "workspace:*", + "@ledgerhq/tsconfig-dsdk": "workspace:*", + "ts-node": "^10.9.2" + }, + "peerDependencies": { + "@ledgerhq/device-management-kit": "workspace:*" + } +} diff --git a/packages/signer/signer-utils/src/index.ts b/packages/signer/signer-utils/src/index.ts new file mode 100644 index 000000000..a83fa9315 --- /dev/null +++ b/packages/signer/signer-utils/src/index.ts @@ -0,0 +1 @@ +export * from "./utils/DerivationPathUtils"; diff --git a/packages/signer/keyring-eth/src/internal/shared/utils/DerivationPathUtils.test.ts b/packages/signer/signer-utils/src/utils/DerivationPathUtils.test.ts similarity index 100% rename from packages/signer/keyring-eth/src/internal/shared/utils/DerivationPathUtils.test.ts rename to packages/signer/signer-utils/src/utils/DerivationPathUtils.test.ts diff --git a/packages/signer/keyring-eth/src/internal/shared/utils/DerivationPathUtils.ts b/packages/signer/signer-utils/src/utils/DerivationPathUtils.ts similarity index 87% rename from packages/signer/keyring-eth/src/internal/shared/utils/DerivationPathUtils.ts rename to packages/signer/signer-utils/src/utils/DerivationPathUtils.ts index 37132ba73..d3dbdafbd 100644 --- a/packages/signer/keyring-eth/src/internal/shared/utils/DerivationPathUtils.ts +++ b/packages/signer/signer-utils/src/utils/DerivationPathUtils.ts @@ -1,5 +1,3 @@ -// TODO: Move to shared package and use in both keyring-btc and keyring-eth - export class DerivationPathUtils { static PADDING = 0x80000000; diff --git a/packages/signer/signer-utils/tsconfig.json b/packages/signer/signer-utils/tsconfig.json new file mode 100644 index 000000000..dd2f89524 --- /dev/null +++ b/packages/signer/signer-utils/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@ledgerhq/tsconfig-dsdk/tsconfig.sdk", + "compilerOptions": { + "baseUrl": ".", + "outDir": "./lib/types", + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "emitDeclarationOnly": true, + "paths": { + "@api/*": ["./src/api/*"], + "@internal/*": ["./src/internal/*"], + "@root/*": ["./*"] + }, + "resolveJsonModule": true + }, + "include": ["src", "jest.*.ts"] +} diff --git a/packages/signer/signer-utils/tsconfig.prod.json b/packages/signer/signer-utils/tsconfig.prod.json new file mode 100644 index 000000000..b90fc83e0 --- /dev/null +++ b/packages/signer/signer-utils/tsconfig.prod.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e090b7b2..989ab3d42 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -388,6 +388,9 @@ importers: '@ledgerhq/prettier-config-dsdk': specifier: workspace:* version: link:../../config/prettier + '@ledgerhq/signer-utils': + specifier: workspace:* + version: link:../signer-utils '@ledgerhq/tsconfig-dsdk': specifier: workspace:* version: link:../../config/typescript @@ -440,6 +443,9 @@ importers: '@ledgerhq/prettier-config-dsdk': specifier: workspace:* version: link:../../config/prettier + '@ledgerhq/signer-utils': + specifier: workspace:* + version: link:../signer-utils '@ledgerhq/tsconfig-dsdk': specifier: workspace:* version: link:../../config/typescript @@ -493,6 +499,30 @@ importers: specifier: ^10.9.2 version: 10.9.2(@types/node@22.7.7)(typescript@5.6.3) + packages/signer/signer-utils: + devDependencies: + '@ledgerhq/device-management-kit': + specifier: workspace:* + version: link:../../core + '@ledgerhq/esbuild-tools': + specifier: workspace:* + version: link:../../tools/esbuild-tools + '@ledgerhq/eslint-config-dsdk': + specifier: workspace:* + version: link:../../config/eslint + '@ledgerhq/jest-config-dsdk': + specifier: workspace:* + version: link:../../config/jest + '@ledgerhq/prettier-config-dsdk': + specifier: workspace:* + version: link:../../config/prettier + '@ledgerhq/tsconfig-dsdk': + specifier: workspace:* + version: link:../../config/typescript + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@22.7.7)(typescript@5.6.3) + packages/tools/esbuild-tools: devDependencies: esbuild: