From 9b9922d185e1934ffc07ae4dde8736037989ec15 Mon Sep 17 00:00:00 2001 From: Maciek Malik Date: Tue, 10 Feb 2026 14:26:39 +0100 Subject: [PATCH 1/6] =?UTF-8?q?=E2=9C=A8=20(signer-aleo):=20Add=20initial?= =?UTF-8?q?=20aleo=20signer=20files=20using=20the=20generator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/docs/references/signers/_meta.js | 1 + .../pages/docs/references/signers/aleo.mdx | 317 ++++++++++++++++++ apps/sample/package.json | 1 + apps/sample/src/app/client-layout.tsx | 25 +- apps/sample/src/app/signers/aleo/page.tsx | 11 + .../src/components/SignerAleoView/index.tsx | 150 +++++++++ .../src/components/SignerView/index.tsx | 5 + .../providers/SignerAleoProvider/index.tsx | 63 ++++ package.json | 1 + packages/signer/signer-aleo/.prettierignore | 2 + packages/signer/signer-aleo/.prettierrc.js | 1 + packages/signer/signer-aleo/CHANGELOG.md | 8 + packages/signer/signer-aleo/README.md | 42 +++ packages/signer/signer-aleo/eslint.config.mjs | 3 + packages/signer/signer-aleo/package.json | 63 ++++ .../signer/signer-aleo/src/api/SignerAleo.ts | 26 ++ .../signer-aleo/src/api/SignerAleoBuilder.ts | 36 ++ .../app-binder/GetAddressDeviceActionTypes.ts | 30 ++ .../GetAppConfigDeviceActionTypes.ts | 30 ++ .../SignMessageDeviceActionTypes.ts | 30 ++ .../SignTransactionDeviceActionTypes.ts | 30 ++ packages/signer/signer-aleo/src/api/index.ts | 3 + .../src/api/model/AddressOptions.ts | 4 + .../signer-aleo/src/api/model/AppConfig.ts | 6 + .../signer-aleo/src/api/model/Signature.ts | 6 + .../src/api/model/TransactionOptions.ts | 4 + packages/signer/signer-aleo/src/index.ts | 4 + .../src/internal/DefaultSignerAleo.ts | 68 ++++ .../src/internal/app-binder/AleoAppBinder.ts | 99 ++++++ .../app-binder/command/GetAddressCommand.ts | 48 +++ .../app-binder/command/GetAppConfigCommand.ts | 40 +++ .../app-binder/command/SignMessageCommand.ts | 46 +++ .../command/SignTransactionCommand.ts | 51 +++ .../command/utils/aleoApplicationErrors.ts | 6 + .../GetAddress/GetAddressDeviceAction.ts | 3 + .../GetAppConfig/GetAppConfigDeviceAction.ts | 3 + .../SignMessage/SignMessageDeviceAction.ts | 3 + .../SignTransactionDeviceAction.ts | 3 + .../internal/app-binder/di/appBinderModule.ts | 9 + .../internal/app-binder/di/appBinderTypes.ts | 3 + .../app-binder/task/SignTransactionTask.ts | 45 +++ .../signer/signer-aleo/src/internal/di.ts | 35 ++ .../signer-aleo/src/internal/externalTypes.ts | 5 + .../use-cases/address/GetAddressUseCase.ts | 28 ++ .../use-cases/address/di/addressModule.ts | 9 + .../use-cases/address/di/addressTypes.ts | 3 + .../use-cases/config/GetAppConfigUseCase.ts | 22 ++ .../use-cases/config/di/configModule.ts | 9 + .../use-cases/config/di/configTypes.ts | 3 + .../use-cases/message/SignMessageUseCase.ts | 27 ++ .../use-cases/message/di/messageModule.ts | 9 + .../use-cases/message/di/messageTypes.ts | 3 + .../transaction/SignTransactionUseCase.ts | 29 ++ .../transaction/di/transactionModule.ts | 9 + .../transaction/di/transactionTypes.ts | 3 + packages/signer/signer-aleo/tsconfig.json | 19 ++ .../signer/signer-aleo/tsconfig.prod.json | 4 + packages/signer/signer-aleo/vitest.config.mjs | 10 + packages/signer/signer-aleo/vitest.setup.mjs | 1 + pnpm-lock.yaml | 49 +++ 60 files changed, 1595 insertions(+), 11 deletions(-) create mode 100644 apps/docs/pages/docs/references/signers/aleo.mdx create mode 100644 apps/sample/src/app/signers/aleo/page.tsx create mode 100644 apps/sample/src/components/SignerAleoView/index.tsx create mode 100644 apps/sample/src/providers/SignerAleoProvider/index.tsx create mode 100644 packages/signer/signer-aleo/.prettierignore create mode 100644 packages/signer/signer-aleo/.prettierrc.js create mode 100644 packages/signer/signer-aleo/CHANGELOG.md create mode 100644 packages/signer/signer-aleo/README.md create mode 100644 packages/signer/signer-aleo/eslint.config.mjs create mode 100644 packages/signer/signer-aleo/package.json create mode 100644 packages/signer/signer-aleo/src/api/SignerAleo.ts create mode 100644 packages/signer/signer-aleo/src/api/SignerAleoBuilder.ts create mode 100644 packages/signer/signer-aleo/src/api/app-binder/GetAddressDeviceActionTypes.ts create mode 100644 packages/signer/signer-aleo/src/api/app-binder/GetAppConfigDeviceActionTypes.ts create mode 100644 packages/signer/signer-aleo/src/api/app-binder/SignMessageDeviceActionTypes.ts create mode 100644 packages/signer/signer-aleo/src/api/app-binder/SignTransactionDeviceActionTypes.ts create mode 100644 packages/signer/signer-aleo/src/api/index.ts create mode 100644 packages/signer/signer-aleo/src/api/model/AddressOptions.ts create mode 100644 packages/signer/signer-aleo/src/api/model/AppConfig.ts create mode 100644 packages/signer/signer-aleo/src/api/model/Signature.ts create mode 100644 packages/signer/signer-aleo/src/api/model/TransactionOptions.ts create mode 100644 packages/signer/signer-aleo/src/index.ts create mode 100644 packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/command/GetAddressCommand.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/command/SignTransactionCommand.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/device-action/GetAddress/GetAddressDeviceAction.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/device-action/GetAppConfig/GetAppConfigDeviceAction.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/device-action/SignMessage/SignMessageDeviceAction.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/device-action/SignTransaction/SignTransactionDeviceAction.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/di/appBinderModule.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/di/appBinderTypes.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/task/SignTransactionTask.ts create mode 100644 packages/signer/signer-aleo/src/internal/di.ts create mode 100644 packages/signer/signer-aleo/src/internal/externalTypes.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/address/GetAddressUseCase.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/address/di/addressModule.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/address/di/addressTypes.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/config/GetAppConfigUseCase.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/config/di/configModule.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/config/di/configTypes.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/message/SignMessageUseCase.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/message/di/messageModule.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/message/di/messageTypes.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/transaction/SignTransactionUseCase.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/transaction/di/transactionModule.ts create mode 100644 packages/signer/signer-aleo/src/internal/use-cases/transaction/di/transactionTypes.ts create mode 100644 packages/signer/signer-aleo/tsconfig.json create mode 100644 packages/signer/signer-aleo/tsconfig.prod.json create mode 100644 packages/signer/signer-aleo/vitest.config.mjs create mode 100644 packages/signer/signer-aleo/vitest.setup.mjs diff --git a/apps/docs/pages/docs/references/signers/_meta.js b/apps/docs/pages/docs/references/signers/_meta.js index 8ee823f71..e2424c0ce 100644 --- a/apps/docs/pages/docs/references/signers/_meta.js +++ b/apps/docs/pages/docs/references/signers/_meta.js @@ -4,4 +4,5 @@ export default { btc: "Signer Bitcoin", hyperliquid: "Signer Hyperliquid", cosmos: "Signer Cosmos", + aleo: "Signer Aleo", }; diff --git a/apps/docs/pages/docs/references/signers/aleo.mdx b/apps/docs/pages/docs/references/signers/aleo.mdx new file mode 100644 index 000000000..3366831b2 --- /dev/null +++ b/apps/docs/pages/docs/references/signers/aleo.mdx @@ -0,0 +1,317 @@ +# Aleo Signer Kit + +This module provides the implementation of the Ledger aleo signer of the Device Management Kit. It enables interaction with the aleo application on a Ledger device including: + +- Retrieving the aleo address using a given derivation path +- Signing a aleo transaction +- Signing a message displayed on a Ledger device +- Retrieving the app configuration + +## 🔹 Index + +1. [How it works](#-how-it-works) +2. [Installation](#-installation) +3. [Initialisation](#-initialisation) +4. [Use Cases](#-use-cases) + - [Get App Configuration](#use-case-1-get-app-configuration) + - [Get Address](#use-case-2-get-address) + - [Sign Transaction](#use-case-3-sign-transaction) + - [Sign Message](#use-case-4-sign-message) +5. [Observable Behavior](#-observable-behavior) +6. [Example](#-example) + +## 🔹 How it works + +The Ledger Aleo Signer utilizes the advanced capabilities of the Ledger device to provide secure operations for end users. It takes advantage of the interface provided by the Device Management Kit to establish communication with the Ledger device and execute various operations. The communication with the Ledger device is performed using [APDU](https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit)s (Application Protocol Data Units), which are encapsulated within the `Command` object. These commands are then organized into tasks, allowing for the execution of complex operations with one or more APDUs. The tasks are further encapsulated within `DeviceAction` objects to handle different real-world scenarios. Finally, the Signer exposes dedicated and independent use cases that can be directly utilized by end users. + +## 🔹 Installation + +> **Note:** This module is not standalone; it depends on the [@ledgerhq/device-management-kit](https://github.com/LedgerHQ/device-sdk-ts/tree/develop/packages/device-management-kit) package, so you need to install it first. + +To install the `device-signer-kit-aleo` package, run the following command: + +```sh +npm install @ledgerhq/device-signer-kit-aleo +``` + +## 🔹 Initialisation + +To initialise a Aleo signer instance, you need a Ledger Device Management Kit instance and the ID of the session of the connected device. Use the `SignerAleoBuilder`: + +```typescript +const signerAleo = new SignerAleoBuilder({ dmk, sessionId }).build(); +``` + +## 🔹 Use Cases + +The `SignerAleoBuilder.build()` method will return a `SignerAleo` instance that exposes 4 dedicated methods, each of which calls an independent use case. Each use case will return an object that contains an observable and a method called `cancel`. + +--- + +### Use Case 1: Get App Configuration + +This method allows users to retrieve the app configuration from the Ledger device. + +```typescript +const { observable, cancel } = signerAleo.getAppConfig(); +``` + +#### **Returns** + +- `observable` Emits DeviceActionState updates, including the following details: + +```typescript +type GetAppConfigCommandResponse = { + // TODO: Define the app configuration response type + // Example: + // version: string; + // flags: number; +}; +``` + +- `cancel` A function to cancel the action on the Ledger device. + +--- + +### Use Case 2: Get Address + +This method allows users to retrieve the aleo address based on a given `derivationPath`. + +```typescript +const { observable, cancel } = signerAleo.getAddress(derivationPath, options); +``` + +#### **Parameters** + +- `derivationPath` + + - **Required** + - **Type:** `string` (e.g., `"m/44'/0'/0'/0/0"`) + - The derivation path used for the aleo address. See [here](https://www.ledger.com/blog/understanding-crypto-addresses-and-derivation-paths) for more information. + +- `options` + + - Optional + - Type: `AddressOptions` + + ```typescript + type AddressOptions = { + checkOnDevice?: boolean; + skipOpenApp?: boolean; + }; + ``` + + - `checkOnDevice`: An optional boolean indicating whether user confirmation on the device is required (`true`) or not (`false`). + - `skipOpenApp`: An optional boolean indicating whether to skip opening the aleo app automatically (`true`) or not (`false`). + +#### **Returns** + +- `observable` Emits DeviceActionState updates, including the following details: + +```typescript +type GetAddressCommandResponse = { + publicKey: Uint8Array; + chainCode?: Uint8Array; +}; +``` + +- `cancel` A function to cancel the action on the Ledger device. + +--- + +### Use Case 3: Sign Transaction + +This method allows users to sign a aleo transaction. + +```typescript +const { observable, cancel } = signerAleo.signTransaction( + derivationPath, + transaction, + options, +); +``` + +#### **Parameters** + +- `derivationPath` + + - **Required** + - **Type:** `string` (e.g., `"m/44'/0'/0'/0/0"`) + - The derivation path used for the aleo transaction. See [here](https://www.ledger.com/blog/understanding-crypto-addresses-and-derivation-paths) for more information. + +- `transaction` + + - **Required** + - **Type:** `Uint8Array` + - The serialized transaction to be signed. + +- `options` + + - Optional + - Type: `TransactionOptions` + + ```typescript + type TransactionOptions = { + skipOpenApp?: boolean; + }; + ``` + + - `skipOpenApp`: An optional boolean indicating whether to skip opening the aleo app automatically (`true`) or not (`false`). + +#### **Returns** + +- `observable` Emits DeviceActionState updates, including the following details: + +```typescript +type Signature = { + r: string; + s: string; + v?: number; +}; +``` + +- `cancel` A function to cancel the action on the Ledger device. + +--- + +### Use Case 4: Sign Message + +This method allows users to sign a text string that is displayed on Ledger devices. + +```typescript +const { observable, cancel } = signerAleo.signMessage( + derivationPath, + message, +); +``` + +#### **Parameters** + +- `derivationPath` + + - **Required** + - **Type:** `string` (e.g., `"m/44'/0'/0'/0/0"`) + - The derivation path used for the aleo message. See [here](https://www.ledger.com/blog/understanding-crypto-addresses-and-derivation-paths) for more information. + +- `message` + + - **Required** + - **Type:** `string | Uint8Array` + - The message to be signed, which will be displayed on the Ledger device. + +#### **Returns** + +- `observable` Emits DeviceActionState updates, including the following details: + +```typescript +type Signature = { + r: string; + s: string; + v?: number; +}; +``` + +- `cancel` A function to cancel the action on the Ledger device. + +--- + +## 🔹 Observable Behavior + +Each method returns an [Observable](https://rxjs.dev/guide/observable) emitting updates structured as [`DeviceActionState`](https://github.com/LedgerHQ/device-sdk-ts/blob/develop/packages/device-management-kit/src/api/device-action/model/DeviceActionState.ts). These updates reflect the operation's progress and status: + +- **NotStarted**: The operation hasn't started. +- **Pending**: The operation is in progress and may require user interaction. +- **Stopped**: The operation was canceled or stopped. +- **Completed**: The operation completed successfully, with results available. +- **Error**: An error occurred. + +**Example Observable Subscription:** + +```typescript +observable.subscribe({ + next: (state: DeviceActionState) => { + switch (state.status) { + case DeviceActionStatus.NotStarted: { + console.log("The action is not started yet."); + break; + } + case DeviceActionStatus.Pending: { + const { + intermediateValue: { requiredUserInteraction }, + } = state; + // Access the intermediate value here, explained below + console.log( + "The action is pending and the intermediate value is: ", + intermediateValue, + ); + break; + } + case DeviceActionStatus.Stopped: { + console.log("The action has been stopped."); + break; + } + case DeviceActionStatus.Completed: { + const { output } = state; + // Access the output of the completed action here + console.log("The action has been completed: ", output); + break; + } + case DeviceActionStatus.Error: { + const { error } = state; + // Access the error here if occurred + console.log("An error occurred during the action: ", error); + break; + } + } + }, +}); +``` + +**Intermediate Values in Pending Status:** + +When the status is DeviceActionStatus.Pending, the state will include an `intermediateValue` object that provides useful information for interaction: + +```typescript +const { requiredUserInteraction } = intermediateValue; + +switch (requiredUserInteraction) { + case UserInteractionRequired.VerifyAddress: { + // User needs to verify the address displayed on the device + console.log("User needs to verify the address displayed on the device."); + break; + } + case UserInteractionRequired.SignTransaction: { + // User needs to sign the transaction displayed on the device + console.log("User needs to sign the transaction displayed on the device."); + break; + } + case UserInteractionRequired.SignPersonalMessage: { + // User needs to sign the message displayed on the device + console.log("User needs to sign the message displayed on the device."); + break; + } + case UserInteractionRequired.None: { + // No user action required + console.log("No user action needed."); + break; + } + case UserInteractionRequired.UnlockDevice: { + // User needs to unlock the device + console.log("The user needs to unlock the device."); + break; + } + case UserInteractionRequired.ConfirmOpenApp: { + // User needs to confirm on the device to open the app + console.log("The user needs to confirm on the device to open the app."); + break; + } + default: + // Type guard to ensure all cases are handled + const uncaughtUserInteraction: never = requiredUserInteraction; + console.error("Unhandled user interaction case:", uncaughtUserInteraction); +} +``` + +## 🔹 Example + +We encourage you to explore the Aleo Signer by trying it out in our online [sample application](https://app.devicesdk.ledger-test.com/). Experience how it works and see its capabilities in action. Of course, you will need a Ledger device connected. diff --git a/apps/sample/package.json b/apps/sample/package.json index 6d74a05cf..92c610fa9 100644 --- a/apps/sample/package.json +++ b/apps/sample/package.json @@ -25,6 +25,7 @@ "@ledgerhq/device-management-kit-devtools-websocket-common": "workspace:^", "@ledgerhq/device-management-kit-devtools-websocket-connector": "workspace:^", "@ledgerhq/device-mockserver-client": "workspace:^", + "@ledgerhq/device-signer-kit-aleo": "workspace:^", "@ledgerhq/device-signer-kit-bitcoin": "workspace:^", "@ledgerhq/device-signer-kit-cosmos": "workspace:^", "@ledgerhq/device-signer-kit-ethereum": "workspace:^", diff --git a/apps/sample/src/app/client-layout.tsx b/apps/sample/src/app/client-layout.tsx index 62c1dbddd..dd088a1eb 100644 --- a/apps/sample/src/app/client-layout.tsx +++ b/apps/sample/src/app/client-layout.tsx @@ -23,6 +23,7 @@ import { CalInterceptorProvider } from "@/providers/CalInterceptorProvider"; import { DmkProvider } from "@/providers/DeviceManagementKitProvider"; import { LedgerKeyringProtocolProvider } from "@/providers/LedgerKeyringProvider"; import { SettingsGate } from "@/providers/SettingsGate"; +import { SignerAleoProvider } from "@/providers/SignerAleoProvider"; import { SignerCosmosProvider } from "@/providers/SignerCosmosProvider"; import { SignerEthProvider } from "@/providers/SignerEthProvider"; import { store } from "@/state/store"; @@ -74,17 +75,19 @@ const ClientRootLayout: React.FC = ({ children }) => { - - - - - - - - {children} - - - + + + + + + + + + {children} + + + + diff --git a/apps/sample/src/app/signers/aleo/page.tsx b/apps/sample/src/app/signers/aleo/page.tsx new file mode 100644 index 000000000..2ae2a55ed --- /dev/null +++ b/apps/sample/src/app/signers/aleo/page.tsx @@ -0,0 +1,11 @@ +"use client"; +import React from "react"; + +import { SessionIdWrapper } from "@/components/SessionIdWrapper"; +import { SignerAleoView } from "@/components/SignerAleoView"; + +const Signer: React.FC = () => { + return ; +}; + +export default Signer; diff --git a/apps/sample/src/components/SignerAleoView/index.tsx b/apps/sample/src/components/SignerAleoView/index.tsx new file mode 100644 index 000000000..3e0bf7505 --- /dev/null +++ b/apps/sample/src/components/SignerAleoView/index.tsx @@ -0,0 +1,150 @@ +import React, { useMemo } from "react"; +import { + type GetAddressDAError, + type GetAddressDAIntermediateValue, + type GetAddressDAOutput, + type GetAppConfigDAError, + type GetAppConfigDAIntermediateValue, + type GetAppConfigDAOutput, + type SignMessageDAError, + type SignMessageDAIntermediateValue, + type SignMessageDAOutput, + type SignTransactionDAError, + type SignTransactionDAIntermediateValue, + type SignTransactionDAOutput, +} from "@ledgerhq/device-signer-kit-aleo"; + +import { DeviceActionsList } from "@/components/DeviceActionsView/DeviceActionsList"; +import { type DeviceActionProps } from "@/components/DeviceActionsView/DeviceActionTester"; +import { useDmk } from "@/providers/DeviceManagementKitProvider"; +import { useSignerAleo } from "@/providers/SignerAleoProvider"; + +export const SignerAleoView: React.FC<{ sessionId: string }> = ({ + sessionId, +}) => { + const dmk = useDmk(); + const signer = useSignerAleo(); + + const deviceModelId = dmk.getConnectedDevice({ + sessionId, + }).modelId; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const deviceActions: DeviceActionProps[] = useMemo( + () => [ + { + title: "Get App Config", + description: "Get the app configuration from the device", + executeDeviceAction: () => { + if (!signer) { + throw new Error("Signer not initialized"); + } + return signer.getAppConfig(); + }, + initialValues: {}, + deviceModelId, + } satisfies DeviceActionProps< + GetAppConfigDAOutput, + Record, + GetAppConfigDAError, + GetAppConfigDAIntermediateValue + >, + { + title: "Get Address", + description: "Get an address from the device", + executeDeviceAction: ({ derivationPath, checkOnDevice, skipOpenApp }) => { + if (!signer) { + throw new Error("Signer not initialized"); + } + return signer.getAddress(derivationPath, { + checkOnDevice, + skipOpenApp, + }); + }, + initialValues: { + derivationPath: "44'/0'/0'/0/0", + checkOnDevice: false, + skipOpenApp: false, + }, + deviceModelId, + } satisfies DeviceActionProps< + GetAddressDAOutput, + { + derivationPath: string; + checkOnDevice?: boolean; + skipOpenApp?: boolean; + }, + GetAddressDAError, + GetAddressDAIntermediateValue + >, + { + title: "Sign Transaction", + description: "Sign a transaction with the device", + executeDeviceAction: ({ derivationPath, transaction, skipOpenApp }) => { + if (!signer) { + throw new Error("Signer not initialized"); + } + // Convert hex string to Uint8Array + const txBytes = transaction.startsWith("0x") + ? new Uint8Array( + transaction + .slice(2) + .match(/.{1,2}/g) + ?.map((byte) => parseInt(byte, 16)) ?? [] + ) + : new Uint8Array( + transaction + .match(/.{1,2}/g) + ?.map((byte) => parseInt(byte, 16)) ?? [] + ); + return signer.signTransaction(derivationPath, txBytes, { + skipOpenApp, + }); + }, + initialValues: { + derivationPath: "44'/0'/0'/0/0", + transaction: "", + skipOpenApp: false, + }, + deviceModelId, + } satisfies DeviceActionProps< + SignTransactionDAOutput, + { + derivationPath: string; + transaction: string; + skipOpenApp?: boolean; + }, + SignTransactionDAError, + SignTransactionDAIntermediateValue + >, + { + title: "Sign Message", + description: "Sign a message with the device", + executeDeviceAction: ({ derivationPath, message }) => { + if (!signer) { + throw new Error("Signer not initialized"); + } + return signer.signMessage(derivationPath, message); + }, + initialValues: { + derivationPath: "44'/0'/0'/0/0", + message: "Hello World", + }, + deviceModelId, + } satisfies DeviceActionProps< + SignMessageDAOutput, + { + derivationPath: string; + message: string; + }, + SignMessageDAError, + SignMessageDAIntermediateValue + >, + ], + [deviceModelId, signer], + ); + + return ( + + ); +}; diff --git a/apps/sample/src/components/SignerView/index.tsx b/apps/sample/src/components/SignerView/index.tsx index d6c639ef5..04f2111eb 100644 --- a/apps/sample/src/components/SignerView/index.tsx +++ b/apps/sample/src/components/SignerView/index.tsx @@ -36,6 +36,11 @@ const SUPPORTED_SIGNERS = [ description: "Access Cosmos signer functionality", icon: , }, + { + title: "Aleo", + description: "Access Aleo signer functionality", + icon: , + }, ]; export const SignerView = () => { diff --git a/apps/sample/src/providers/SignerAleoProvider/index.tsx b/apps/sample/src/providers/SignerAleoProvider/index.tsx new file mode 100644 index 000000000..2addf7890 --- /dev/null +++ b/apps/sample/src/providers/SignerAleoProvider/index.tsx @@ -0,0 +1,63 @@ +"use client"; + +import React, { + createContext, + type PropsWithChildren, + useContext, + useEffect, + useState, +} from "react"; +import { useSelector } from "react-redux"; +import { + type SignerAleo, + SignerAleoBuilder, +} from "@ledgerhq/device-signer-kit-aleo"; + +import { useDmk } from "@/providers/DeviceManagementKitProvider"; +import { selectSelectedSessionId } from "@/state/sessions/selectors"; + +type SignerAleoContextType = { + signer: SignerAleo | null; +}; + +const initialState: SignerAleoContextType = { + signer: null, +}; + +const SignerAleoContext = createContext(initialState); + +export const SignerAleoProvider: React.FC = ({ + children, +}) => { + const dmk = useDmk(); + const sessionId = useSelector(selectSelectedSessionId); + + const [signer, setSigner] = useState(null); + + useEffect(() => { + if (!sessionId || !dmk) { + setSigner(null); + return; + } + + const newSigner = new SignerAleoBuilder({ + dmk, + sessionId, + }).build(); + setSigner(newSigner); + }, [dmk, sessionId]); + + return ( + + {children} + + ); +}; + +export const useSignerAleo = (): SignerAleo | null => { + return useContext(SignerAleoContext).signer; +}; diff --git a/package.json b/package.json index 6b2086666..3ddd921b6 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "devtools": "pnpm --filter @ledgerhq/device-management-kit-devtools", "speculos-device-controller": "pnpm --filter @ledgerhq/speculos-device-controller", "context-module": "pnpm --filter @ledgerhq/context-module", + "signer-aleo": "pnpm --filter @ledgerhq/device-signer-kit-aleo", "signer-btc": "pnpm --filter @ledgerhq/device-signer-kit-bitcoin", "signer-cosmos": "pnpm --filter @ledgerhq/device-signer-kit-cosmos", "signer-eth": "pnpm --filter @ledgerhq/device-signer-kit-ethereum", diff --git a/packages/signer/signer-aleo/.prettierignore b/packages/signer/signer-aleo/.prettierignore new file mode 100644 index 000000000..3b4e8dcf9 --- /dev/null +++ b/packages/signer/signer-aleo/.prettierignore @@ -0,0 +1,2 @@ +lib/ +node_modules/ diff --git a/packages/signer/signer-aleo/.prettierrc.js b/packages/signer/signer-aleo/.prettierrc.js new file mode 100644 index 000000000..98bb39000 --- /dev/null +++ b/packages/signer/signer-aleo/.prettierrc.js @@ -0,0 +1 @@ +module.exports = require("@ledgerhq/prettier-config-dsdk"); diff --git a/packages/signer/signer-aleo/CHANGELOG.md b/packages/signer/signer-aleo/CHANGELOG.md new file mode 100644 index 000000000..c6c135965 --- /dev/null +++ b/packages/signer/signer-aleo/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.1.0] - 2026-02-05 + +### Added +- Initial signer implementation for aleo diff --git a/packages/signer/signer-aleo/README.md b/packages/signer/signer-aleo/README.md new file mode 100644 index 000000000..7b0521654 --- /dev/null +++ b/packages/signer/signer-aleo/README.md @@ -0,0 +1,42 @@ +# Signer aleo + +This package provides a signer implementation for aleo. + +## Installation + +```bash +pnpm add @ledgerhq/device-signer-kit-aleo +``` + +## Usage + +```typescript +import { SignerAleoBuilder } from "@ledgerhq/device-signer-kit-aleo"; + +const signer = new SignerAleoBuilder({ dmk, sessionId }).build(); + +// Get address +const address = await signer.getAddress("m/44'/0'/0'/0/0"); + +// Sign transaction +const signature = await signer.signTransaction( + "m/44'/0'/0'/0/0", + transactionBytes +); +``` + +## Development + +```bash +# Install dependencies +pnpm install + +# Build +pnpm build + +# Test +pnpm test + +# Lint +pnpm lint +``` diff --git a/packages/signer/signer-aleo/eslint.config.mjs b/packages/signer/signer-aleo/eslint.config.mjs new file mode 100644 index 000000000..0da70bba7 --- /dev/null +++ b/packages/signer/signer-aleo/eslint.config.mjs @@ -0,0 +1,3 @@ +import { eslintConfigDmk } from "@ledgerhq/eslint-config-dsdk"; + +export default eslintConfigDmk; diff --git a/packages/signer/signer-aleo/package.json b/packages/signer/signer-aleo/package.json new file mode 100644 index 000000000..5f1881d0f --- /dev/null +++ b/packages/signer/signer-aleo/package.json @@ -0,0 +1,63 @@ +{ + "name": "@ledgerhq/device-signer-kit-aleo", + "version": "0.1.0", + "private": false, + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/LedgerHQ/device-sdk-ts.git" + }, + "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 ldmk-tool build --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json", + "dev": "concurrently \"pnpm watch:builds\" \"pnpm watch:types\"", + "watch:builds": "pnpm ldmk-tool 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", + "prettier": "prettier . --check", + "prettier:fix": "prettier . --write", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage" + }, + "dependencies": { + "@ledgerhq/signer-utils": "workspace:^", + "inversify": "catalog:", + "purify-ts": "catalog:", + "reflect-metadata": "catalog:", + "xstate": "catalog:", + "@ledgerhq/context-module": "workspace:^" + }, + "devDependencies": { + "@ledgerhq/device-management-kit": "workspace:^", + "@ledgerhq/ldmk-tool": "workspace:^", + "@ledgerhq/eslint-config-dsdk": "workspace:^", + "@ledgerhq/prettier-config-dsdk": "workspace:^", + "@ledgerhq/tsconfig-dsdk": "workspace:^", + "@ledgerhq/vitest-config-dmk": "workspace:^", + "rxjs": "catalog:", + "ts-node": "catalog:", + "@ledgerhq/context-module": "workspace:^" + }, + "peerDependencies": { + "@ledgerhq/device-management-kit": "workspace:^", + "@ledgerhq/context-module": "workspace:^" + } +} diff --git a/packages/signer/signer-aleo/src/api/SignerAleo.ts b/packages/signer/signer-aleo/src/api/SignerAleo.ts new file mode 100644 index 000000000..d3c7b5d4e --- /dev/null +++ b/packages/signer/signer-aleo/src/api/SignerAleo.ts @@ -0,0 +1,26 @@ +import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; +import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceActionTypes"; +import { type AddressOptions } from "@api/model/AddressOptions"; +import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; +import { type TransactionOptions } from "@api/model/TransactionOptions"; +import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; + +export interface SignerAleo { + getAppConfig: () => GetAppConfigDAReturnType; + + getAddress: ( + derivationPath: string, + options?: AddressOptions, + ) => GetAddressDAReturnType; + + signTransaction: ( + derivationPath: string, + transaction: Uint8Array, + options?: TransactionOptions, + ) => SignTransactionDAReturnType; + + signMessage: ( + derivationPath: string, + message: string | Uint8Array, + ) => SignMessageDAReturnType; +} diff --git a/packages/signer/signer-aleo/src/api/SignerAleoBuilder.ts b/packages/signer/signer-aleo/src/api/SignerAleoBuilder.ts new file mode 100644 index 000000000..af1d3362d --- /dev/null +++ b/packages/signer/signer-aleo/src/api/SignerAleoBuilder.ts @@ -0,0 +1,36 @@ +import { + type DeviceManagementKit, + type DeviceSessionId, +} from "@ledgerhq/device-management-kit"; + +import { DefaultSignerAleo } from "@internal/DefaultSignerAleo"; + +type SignerAleoBuilderConstructorArgs = { + dmk: DeviceManagementKit; + sessionId: DeviceSessionId; +}; + +/** + * Builder for the `SignerAleo` class. + */ +export class SignerAleoBuilder { + private readonly _dmk: DeviceManagementKit; + private readonly _sessionId: DeviceSessionId; + + constructor({ dmk, sessionId }: SignerAleoBuilderConstructorArgs) { + this._dmk = dmk; + this._sessionId = sessionId; + } + + /** + * Build the signer instance + * + * @returns the signer instance + */ + public build() { + return new DefaultSignerAleo({ + dmk: this._dmk, + sessionId: this._sessionId, + }); + } +} diff --git a/packages/signer/signer-aleo/src/api/app-binder/GetAddressDeviceActionTypes.ts b/packages/signer/signer-aleo/src/api/app-binder/GetAddressDeviceActionTypes.ts new file mode 100644 index 000000000..81d31cc76 --- /dev/null +++ b/packages/signer/signer-aleo/src/api/app-binder/GetAddressDeviceActionTypes.ts @@ -0,0 +1,30 @@ +import { + type CommandErrorResult, + type ExecuteDeviceActionReturnType, + type OpenAppDAError, + type SendCommandInAppDAIntermediateValue, + type SendCommandInAppDAOutput, + type UserInteractionRequired, +} from "@ledgerhq/device-management-kit"; + +import { type GetAddressCommandResponse } from "@internal/app-binder/command/GetAddressCommand"; +import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors"; + +type GetAddressDAUserInteractionRequired = + | UserInteractionRequired.None | UserInteractionRequired.VerifyAddress; + +export type GetAddressDAOutput = + SendCommandInAppDAOutput; + +export type GetAddressDAError = + | OpenAppDAError + | CommandErrorResult["error"]; + +export type GetAddressDAIntermediateValue = + SendCommandInAppDAIntermediateValue; + +export type GetAddressDAReturnType = ExecuteDeviceActionReturnType< + GetAddressDAOutput, + GetAddressDAError, + GetAddressDAIntermediateValue +>; diff --git a/packages/signer/signer-aleo/src/api/app-binder/GetAppConfigDeviceActionTypes.ts b/packages/signer/signer-aleo/src/api/app-binder/GetAppConfigDeviceActionTypes.ts new file mode 100644 index 000000000..f4b9f0bfa --- /dev/null +++ b/packages/signer/signer-aleo/src/api/app-binder/GetAppConfigDeviceActionTypes.ts @@ -0,0 +1,30 @@ +import { + type CommandErrorResult, + type ExecuteDeviceActionReturnType, + type OpenAppDAError, + type SendCommandInAppDAIntermediateValue, + type SendCommandInAppDAOutput, + type UserInteractionRequired, +} from "@ledgerhq/device-management-kit"; + +import { type GetAppConfigCommandResponse } from "@internal/app-binder/command/GetAppConfigCommand"; +import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors"; + +type GetAppConfigDAUserInteractionRequired = + | UserInteractionRequired.None; + +export type GetAppConfigDAOutput = + SendCommandInAppDAOutput; + +export type GetAppConfigDAError = + | OpenAppDAError + | CommandErrorResult["error"]; + +export type GetAppConfigDAIntermediateValue = + SendCommandInAppDAIntermediateValue; + +export type GetAppConfigDAReturnType = ExecuteDeviceActionReturnType< + GetAppConfigDAOutput, + GetAppConfigDAError, + GetAppConfigDAIntermediateValue +>; diff --git a/packages/signer/signer-aleo/src/api/app-binder/SignMessageDeviceActionTypes.ts b/packages/signer/signer-aleo/src/api/app-binder/SignMessageDeviceActionTypes.ts new file mode 100644 index 000000000..ed93ad5d5 --- /dev/null +++ b/packages/signer/signer-aleo/src/api/app-binder/SignMessageDeviceActionTypes.ts @@ -0,0 +1,30 @@ +import { + type CommandErrorResult, + type ExecuteDeviceActionReturnType, + type OpenAppDAError, + type SendCommandInAppDAIntermediateValue, + type SendCommandInAppDAOutput, + type UserInteractionRequired, +} from "@ledgerhq/device-management-kit"; + +import { type SignMessageCommandResponse } from "@internal/app-binder/command/SignMessageCommand"; +import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors"; + +type SignMessageDAUserInteractionRequired = + | UserInteractionRequired.None | UserInteractionRequired.SignPersonalMessage; + +export type SignMessageDAOutput = + SendCommandInAppDAOutput; + +export type SignMessageDAError = + | OpenAppDAError + | CommandErrorResult["error"]; + +export type SignMessageDAIntermediateValue = + SendCommandInAppDAIntermediateValue; + +export type SignMessageDAReturnType = ExecuteDeviceActionReturnType< + SignMessageDAOutput, + SignMessageDAError, + SignMessageDAIntermediateValue +>; diff --git a/packages/signer/signer-aleo/src/api/app-binder/SignTransactionDeviceActionTypes.ts b/packages/signer/signer-aleo/src/api/app-binder/SignTransactionDeviceActionTypes.ts new file mode 100644 index 000000000..8d9fc4fdf --- /dev/null +++ b/packages/signer/signer-aleo/src/api/app-binder/SignTransactionDeviceActionTypes.ts @@ -0,0 +1,30 @@ +import { + type CommandErrorResult, + type ExecuteDeviceActionReturnType, + type OpenAppDAError, + type OpenAppDARequiredInteraction, + type UserInteractionRequired, +} from "@ledgerhq/device-management-kit"; + +import { type Signature } from "@api/model/Signature"; +import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors"; + +export type SignTransactionDAOutput = Signature; + +export type SignTransactionDAError = + | OpenAppDAError + | CommandErrorResult["error"]; + +type SignTransactionDARequiredInteraction = + | OpenAppDARequiredInteraction + | UserInteractionRequired.SignTransaction; + +export type SignTransactionDAIntermediateValue = { + requiredUserInteraction: SignTransactionDARequiredInteraction; +}; + +export type SignTransactionDAReturnType = ExecuteDeviceActionReturnType< + SignTransactionDAOutput, + SignTransactionDAError, + SignTransactionDAIntermediateValue +>; diff --git a/packages/signer/signer-aleo/src/api/index.ts b/packages/signer/signer-aleo/src/api/index.ts new file mode 100644 index 000000000..16a927682 --- /dev/null +++ b/packages/signer/signer-aleo/src/api/index.ts @@ -0,0 +1,3 @@ +export * from "@api/SignerAleo"; +export * from "@api/SignerAleoBuilder"; +// Export other types as needed diff --git a/packages/signer/signer-aleo/src/api/model/AddressOptions.ts b/packages/signer/signer-aleo/src/api/model/AddressOptions.ts new file mode 100644 index 000000000..0a7f9c75e --- /dev/null +++ b/packages/signer/signer-aleo/src/api/model/AddressOptions.ts @@ -0,0 +1,4 @@ +export type AddressOptions = { + checkOnDevice?: boolean; + skipOpenApp?: boolean; +}; diff --git a/packages/signer/signer-aleo/src/api/model/AppConfig.ts b/packages/signer/signer-aleo/src/api/model/AppConfig.ts new file mode 100644 index 000000000..ed4ad517b --- /dev/null +++ b/packages/signer/signer-aleo/src/api/model/AppConfig.ts @@ -0,0 +1,6 @@ +export type AppConfig = { + // Define your app configuration fields here + // Example: + // version: string; + // flags: number; +}; diff --git a/packages/signer/signer-aleo/src/api/model/Signature.ts b/packages/signer/signer-aleo/src/api/model/Signature.ts new file mode 100644 index 000000000..d534ab5c2 --- /dev/null +++ b/packages/signer/signer-aleo/src/api/model/Signature.ts @@ -0,0 +1,6 @@ +export type Signature = { + r: string; + s: string; + v?: number; + // Adjust based on your blockchain's signature format +}; diff --git a/packages/signer/signer-aleo/src/api/model/TransactionOptions.ts b/packages/signer/signer-aleo/src/api/model/TransactionOptions.ts new file mode 100644 index 000000000..f7ae2dc93 --- /dev/null +++ b/packages/signer/signer-aleo/src/api/model/TransactionOptions.ts @@ -0,0 +1,4 @@ +export type TransactionOptions = { + skipOpenApp?: boolean; + // Add other options as needed +}; diff --git a/packages/signer/signer-aleo/src/index.ts b/packages/signer/signer-aleo/src/index.ts new file mode 100644 index 000000000..d1f800da1 --- /dev/null +++ b/packages/signer/signer-aleo/src/index.ts @@ -0,0 +1,4 @@ +// inversify requirement +import "reflect-metadata"; + +export * from "@api/index"; diff --git a/packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts b/packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts new file mode 100644 index 000000000..4265ce9ea --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts @@ -0,0 +1,68 @@ +import { + type DeviceManagementKit, + type DeviceSessionId, +} from "@ledgerhq/device-management-kit"; +import { type Container } from "inversify"; +import { type SignerAleo } from "@api/SignerAleo"; +import { makeContainer } from "@internal/di"; +import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; +import { configTypes } from "@internal/use-cases/config/di/configTypes"; +import { type GetAppConfigUseCase } from "@internal/use-cases/config/GetAppConfigUseCase"; +import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceActionTypes"; +import { type AddressOptions } from "@api/model/AddressOptions"; +import { addressTypes } from "@internal/use-cases/address/di/addressTypes"; +import { type GetAddressUseCase } from "@internal/use-cases/address/GetAddressUseCase"; +import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; +import { type TransactionOptions } from "@api/model/TransactionOptions"; +import { transactionTypes } from "@internal/use-cases/transaction/di/transactionTypes"; +import { type SignTransactionUseCase } from "@internal/use-cases/transaction/SignTransactionUseCase"; +import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; +import { messageTypes } from "@internal/use-cases/message/di/messageTypes"; +import { type SignMessageUseCase } from "@internal/use-cases/message/SignMessageUseCase"; + +type DefaultSignerAleoConstructorArgs = { + dmk: DeviceManagementKit; + sessionId: DeviceSessionId; +}; + +export class DefaultSignerAleo implements SignerAleo { + private readonly _container: Container; + + constructor({ dmk, sessionId }: DefaultSignerAleoConstructorArgs) { + this._container = makeContainer({ dmk, sessionId }); + } + + getAppConfig(): GetAppConfigDAReturnType { + return this._container + .get(configTypes.GetAppConfigUseCase) + .execute(); + } + + getAddress( + derivationPath: string, + options?: AddressOptions, + ): GetAddressDAReturnType { + return this._container + .get(addressTypes.GetAddressUseCase) + .execute(derivationPath, options); + } + + signTransaction( + derivationPath: string, + transaction: Uint8Array, + options?: TransactionOptions, + ): SignTransactionDAReturnType { + return this._container + .get(transactionTypes.SignTransactionUseCase) + .execute(derivationPath, transaction, options); + } + + signMessage( + derivationPath: string, + message: string | Uint8Array, + ): SignMessageDAReturnType { + return this._container + .get(messageTypes.SignMessageUseCase) + .execute(derivationPath, message); + } +} diff --git a/packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts b/packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts new file mode 100644 index 000000000..5958cfe51 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts @@ -0,0 +1,99 @@ +import { + type DeviceManagementKit, + type DeviceSessionId, + SendCommandInAppDeviceAction, + CallTaskInAppDeviceAction, + UserInteractionRequired, +} from "@ledgerhq/device-management-kit"; +import { inject, injectable } from "inversify"; +import { externalTypes } from "@internal/externalTypes"; +import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; +import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceActionTypes"; +import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; +import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; + +import { GetAppConfigCommand } from "./command/GetAppConfigCommand"; +import { GetAddressCommand } from "./command/GetAddressCommand"; +import { SignTransactionTask } from "./task/SignTransactionTask"; +import { SignMessageCommand } from "./command/SignMessageCommand"; + +@injectable() +export class AleoAppBinder { + constructor( + @inject(externalTypes.Dmk) private dmk: DeviceManagementKit, + @inject(externalTypes.SessionId) private sessionId: DeviceSessionId, + ) {} + + getAppConfig(args: { + skipOpenApp: boolean; + }): GetAppConfigDAReturnType { + return this.dmk.executeDeviceAction({ + sessionId: this.sessionId, + deviceAction: new SendCommandInAppDeviceAction({ + input: { + command: new GetAppConfigCommand(), + appName: "Aleo", + requiredUserInteraction: UserInteractionRequired.None, + skipOpenApp: args.skipOpenApp, + }, + }), + }); + } + + getAddress(args: { + derivationPath: string; + checkOnDevice: boolean; + skipOpenApp: boolean; + }): GetAddressDAReturnType { + return this.dmk.executeDeviceAction({ + sessionId: this.sessionId, + deviceAction: new SendCommandInAppDeviceAction({ + input: { + command: new GetAddressCommand(args), + appName: "Aleo", + requiredUserInteraction: args.checkOnDevice + ? UserInteractionRequired.VerifyAddress + : UserInteractionRequired.None, + skipOpenApp: args.skipOpenApp, + }, + }), + }); + } + + signTransaction(args: { + derivationPath: string; + transaction: Uint8Array; + skipOpenApp?: boolean; + }): SignTransactionDAReturnType { + return this.dmk.executeDeviceAction({ + sessionId: this.sessionId, + deviceAction: new CallTaskInAppDeviceAction({ + input: { + task: async (internalApi) => + new SignTransactionTask(internalApi, args).run(), + appName: "Aleo", + requiredUserInteraction: UserInteractionRequired.SignTransaction, + skipOpenApp: args.skipOpenApp ?? false, + }, + }), + }); + } + + signMessage(args: { + derivationPath: string; + message: string | Uint8Array; + skipOpenApp: boolean; + }): SignMessageDAReturnType { + return this.dmk.executeDeviceAction({ + sessionId: this.sessionId, + deviceAction: new SendCommandInAppDeviceAction({ + input: { + command: new SignMessageCommand(args), + appName: "Aleo", + requiredUserInteraction: UserInteractionRequired.SignPersonalMessage, + skipOpenApp: args.skipOpenApp, + }, + }), + }); + } +} diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAddressCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAddressCommand.ts new file mode 100644 index 000000000..eb2a588fa --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAddressCommand.ts @@ -0,0 +1,48 @@ +import { + type Apdu, + type ApduResponse, + type Command, + type CommandResult, +} from "@ledgerhq/device-management-kit"; + +import { type AleoErrorCodes } from "./utils/aleoApplicationErrors"; + +export type GetAddressCommandArgs = { + readonly derivationPath: string; + readonly checkOnDevice?: boolean; +}; + +export type GetAddressCommandResponse = { + readonly publicKey: Uint8Array; + readonly chainCode?: Uint8Array; +}; + +export class GetAddressCommand + implements + Command +{ + readonly name = "GetAddress"; + + private readonly args: GetAddressCommandArgs; + + constructor(args: GetAddressCommandArgs) { + this.args = args; + } + + getApdu(): Apdu { + // TODO: Implement APDU construction based on your blockchain's protocol + // Example structure: + // const builder = new ApduBuilder({ cla: 0xe0, ins: 0x02, p1: 0x00, p2: 0x00 }); + // Add derivation path and other data to builder + // return builder.build(); + throw new Error("GetAddressCommand.getApdu() not implemented"); + } + + parseResponse( + _apduResponse: ApduResponse, + ): CommandResult { + // TODO: Implement response parsing based on your blockchain's protocol + // return CommandResultFactory({ data: { ... } }); + throw new Error("GetAddressCommand.parseResponse() not implemented"); + } +} diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts new file mode 100644 index 000000000..6c8b0ac52 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts @@ -0,0 +1,40 @@ +import { + type Apdu, + type ApduResponse, + type Command, + type CommandResult, +} from "@ledgerhq/device-management-kit"; + +import { type AleoErrorCodes } from "./utils/aleoApplicationErrors"; + +export type GetAppConfigCommandResponse = { + // Define your app configuration response fields here + // Example: + // version: string; + // flags: number; +}; + +export class GetAppConfigCommand + implements + Command +{ + readonly name = "GetAppConfig"; + + + getApdu(): Apdu { + // TODO: Implement APDU construction based on your blockchain's protocol + // Example structure: + // const builder = new ApduBuilder({ cla: 0xe0, ins: 0x02, p1: 0x00, p2: 0x00 }); + // Add derivation path and other data to builder + // return builder.build(); + throw new Error("GetAppConfigCommand.getApdu() not implemented"); + } + + parseResponse( + _apduResponse: ApduResponse, + ): CommandResult { + // TODO: Implement response parsing based on your blockchain's protocol + // return CommandResultFactory({ data: { ... } }); + throw new Error("GetAppConfigCommand.parseResponse() not implemented"); + } +} diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts new file mode 100644 index 000000000..d28c4e4af --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts @@ -0,0 +1,46 @@ +import { + type Apdu, + type ApduResponse, + type Command, + type CommandResult, +} from "@ledgerhq/device-management-kit"; + +import { type Signature } from "@api/model/Signature"; +import { type AleoErrorCodes } from "./utils/aleoApplicationErrors"; + +export type SignMessageCommandArgs = { + derivationPath: string; + message: string | Uint8Array; +}; + +export type SignMessageCommandResponse = Signature; + +export class SignMessageCommand + implements + Command +{ + readonly name = "SignMessage"; + + private readonly args: SignMessageCommandArgs; + + constructor(args: SignMessageCommandArgs) { + this.args = args; + } + + getApdu(): Apdu { + // TODO: Implement APDU construction based on your blockchain's protocol + // Example structure: + // const builder = new ApduBuilder({ cla: 0xe0, ins: 0x02, p1: 0x00, p2: 0x00 }); + // Add derivation path and other data to builder + // return builder.build(); + throw new Error("SignMessageCommand.getApdu() not implemented"); + } + + parseResponse( + _apduResponse: ApduResponse, + ): CommandResult { + // TODO: Implement response parsing based on your blockchain's protocol + // return CommandResultFactory({ data: { ... } }); + throw new Error("SignMessageCommand.parseResponse() not implemented"); + } +} diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/SignTransactionCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/SignTransactionCommand.ts new file mode 100644 index 000000000..a0047beca --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/SignTransactionCommand.ts @@ -0,0 +1,51 @@ +import { + type Apdu, + type ApduResponse, + type Command, + type CommandResult, +} from "@ledgerhq/device-management-kit"; + +import { type AleoErrorCodes } from "./utils/aleoApplicationErrors"; + +export type SignTransactionCommandArgs = { + derivationPath: string; + transaction: Uint8Array; +}; + +export type SignTransactionCommandResponse = { + signature: { + r: string; + s: string; + v?: number; + }; +}; + +export class SignTransactionCommand + implements + Command +{ + readonly name = "SignTransaction"; + + private readonly args: SignTransactionCommandArgs; + + constructor(args: SignTransactionCommandArgs) { + this.args = args; + } + + getApdu(): Apdu { + // TODO: Implement APDU construction based on your blockchain's protocol + // Example structure: + // const builder = new ApduBuilder({ cla: 0xe0, ins: 0x02, p1: 0x00, p2: 0x00 }); + // Add derivation path and other data to builder + // return builder.build(); + throw new Error("SignTransactionCommand.getApdu() not implemented"); + } + + parseResponse( + _apduResponse: ApduResponse, + ): CommandResult { + // TODO: Implement response parsing based on your blockchain's protocol + // return CommandResultFactory({ data: { ... } }); + throw new Error("SignTransactionCommand.parseResponse() not implemented"); + } +} diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.ts new file mode 100644 index 000000000..c7261ee54 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.ts @@ -0,0 +1,6 @@ +export enum AleoErrorCodes { + // Define your error codes here + // Example: + // INVALID_DERIVATION_PATH = 0x6a80, + // TRANSACTION_PARSING_ERROR = 0x6a81, +} diff --git a/packages/signer/signer-aleo/src/internal/app-binder/device-action/GetAddress/GetAddressDeviceAction.ts b/packages/signer/signer-aleo/src/internal/app-binder/device-action/GetAddress/GetAddressDeviceAction.ts new file mode 100644 index 000000000..580962828 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/device-action/GetAddress/GetAddressDeviceAction.ts @@ -0,0 +1,3 @@ +// TODO: Implement GetAddressDeviceAction if needed +// This is a placeholder - you may not need a custom device action for getAddress +// if SendCommandInAppDeviceAction is sufficient diff --git a/packages/signer/signer-aleo/src/internal/app-binder/device-action/GetAppConfig/GetAppConfigDeviceAction.ts b/packages/signer/signer-aleo/src/internal/app-binder/device-action/GetAppConfig/GetAppConfigDeviceAction.ts new file mode 100644 index 000000000..2dd21ceaf --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/device-action/GetAppConfig/GetAppConfigDeviceAction.ts @@ -0,0 +1,3 @@ +// TODO: Implement GetAppConfigDeviceAction if needed +// This is a placeholder - you may not need a custom device action for getAppConfig +// if SendCommandInAppDeviceAction is sufficient diff --git a/packages/signer/signer-aleo/src/internal/app-binder/device-action/SignMessage/SignMessageDeviceAction.ts b/packages/signer/signer-aleo/src/internal/app-binder/device-action/SignMessage/SignMessageDeviceAction.ts new file mode 100644 index 000000000..2251573e0 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/device-action/SignMessage/SignMessageDeviceAction.ts @@ -0,0 +1,3 @@ +// TODO: Implement SignMessageDeviceAction if needed +// This is a placeholder - you may not need a custom device action for signMessage +// if SendCommandInAppDeviceAction is sufficient diff --git a/packages/signer/signer-aleo/src/internal/app-binder/device-action/SignTransaction/SignTransactionDeviceAction.ts b/packages/signer/signer-aleo/src/internal/app-binder/device-action/SignTransaction/SignTransactionDeviceAction.ts new file mode 100644 index 000000000..2dcd298dd --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/device-action/SignTransaction/SignTransactionDeviceAction.ts @@ -0,0 +1,3 @@ +// TODO: Implement SignTransactionDeviceAction if needed +// This is a placeholder - you may not need a custom device action for signTransaction +// if CallTaskInAppDeviceAction with SignTransactionTask is sufficient diff --git a/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderModule.ts b/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderModule.ts new file mode 100644 index 000000000..8a8c6e884 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderModule.ts @@ -0,0 +1,9 @@ +import { ContainerModule } from "inversify"; + +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; +import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; + +export const appBindingModuleFactory = () => + new ContainerModule(({ bind }) => { + bind(appBinderTypes.AppBinding).to(AleoAppBinder); + }); diff --git a/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderTypes.ts b/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderTypes.ts new file mode 100644 index 000000000..565f9585a --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderTypes.ts @@ -0,0 +1,3 @@ +export const appBinderTypes = { + AppBinding: Symbol.for("AppBinding"), +} as const; diff --git a/packages/signer/signer-aleo/src/internal/app-binder/task/SignTransactionTask.ts b/packages/signer/signer-aleo/src/internal/app-binder/task/SignTransactionTask.ts new file mode 100644 index 000000000..4a5a786ad --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/task/SignTransactionTask.ts @@ -0,0 +1,45 @@ +import { + type CommandResult, + CommandResultFactory, + type InternalApi, + isSuccessCommandResult, +} from "@ledgerhq/device-management-kit"; + +import { type Signature } from "@api/model/Signature"; +import { SignTransactionCommand } from "@internal/app-binder/command/SignTransactionCommand"; +import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors"; + +type SignTransactionTaskArgs = { + derivationPath: string; + transaction: Uint8Array; +}; + +export class SignTransactionTask { + constructor( + private api: InternalApi, + private args: SignTransactionTaskArgs, + ) {} + + async run(): Promise> { + // TODO: Adapt this implementation to your blockchain's signing protocol + // For transactions larger than a single APDU, you may need to: + // 1. Split the transaction into chunks + // 2. Send each chunk with appropriate first/continue flags + // 3. Collect the final signature from the last response + + const result = await this.api.sendCommand( + new SignTransactionCommand({ + derivationPath: this.args.derivationPath, + transaction: this.args.transaction, + }), + ); + + if (!isSuccessCommandResult(result)) { + return result; + } + + return CommandResultFactory({ + data: result.data.signature, + }); + } +} diff --git a/packages/signer/signer-aleo/src/internal/di.ts b/packages/signer/signer-aleo/src/internal/di.ts new file mode 100644 index 000000000..d43a1e712 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/di.ts @@ -0,0 +1,35 @@ +import { + type DeviceManagementKit, + type DeviceSessionId, +} from "@ledgerhq/device-management-kit"; +import { Container } from "inversify"; +import { appBindingModuleFactory } from "@internal/app-binder/di/appBinderModule"; +import { externalTypes } from "@internal/externalTypes"; +import { configModuleFactory } from "@internal/use-cases/config/di/configModule"; +import { addressModuleFactory } from "@internal/use-cases/address/di/addressModule"; +import { transactionModuleFactory } from "@internal/use-cases/transaction/di/transactionModule"; +import { messageModuleFactory } from "@internal/use-cases/message/di/messageModule"; + +type MakeContainerProps = { + dmk: DeviceManagementKit; + sessionId: DeviceSessionId; +}; + +export const makeContainer = ({ dmk, sessionId }: MakeContainerProps) => { + const container = new Container(); + + container.bind(externalTypes.Dmk).toConstantValue(dmk); + container + .bind(externalTypes.SessionId) + .toConstantValue(sessionId); + + container.loadSync( + appBindingModuleFactory(), + configModuleFactory(), + addressModuleFactory(), + transactionModuleFactory(), + messageModuleFactory(), + ); + + return container; +}; diff --git a/packages/signer/signer-aleo/src/internal/externalTypes.ts b/packages/signer/signer-aleo/src/internal/externalTypes.ts new file mode 100644 index 000000000..6ccea36a4 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/externalTypes.ts @@ -0,0 +1,5 @@ +export const externalTypes = { + Dmk: Symbol.for("Dmk"), + SessionId: Symbol.for("SessionId"), + ContextModule: Symbol.for("ContextModule"), +} as const; diff --git a/packages/signer/signer-aleo/src/internal/use-cases/address/GetAddressUseCase.ts b/packages/signer/signer-aleo/src/internal/use-cases/address/GetAddressUseCase.ts new file mode 100644 index 000000000..3ef75420f --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/address/GetAddressUseCase.ts @@ -0,0 +1,28 @@ +import { inject, injectable } from "inversify"; + +import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceActionTypes"; +import { type AddressOptions } from "@api/model/AddressOptions"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; +import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; + +@injectable() +export class GetAddressUseCase { + private readonly _appBinder: AleoAppBinder; + + constructor( + @inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder, + ) { + this._appBinder = appBinder; + } + + execute( + derivationPath: string, + options?: AddressOptions, + ): GetAddressDAReturnType { + return this._appBinder.getAddress({ + derivationPath, + checkOnDevice: options?.checkOnDevice ?? false, + skipOpenApp: options?.skipOpenApp ?? false, + }); + } +} diff --git a/packages/signer/signer-aleo/src/internal/use-cases/address/di/addressModule.ts b/packages/signer/signer-aleo/src/internal/use-cases/address/di/addressModule.ts new file mode 100644 index 000000000..9d769f0f7 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/address/di/addressModule.ts @@ -0,0 +1,9 @@ +import { ContainerModule } from "inversify"; + +import { addressTypes } from "@internal/use-cases/address/di/addressTypes"; +import { GetAddressUseCase } from "@internal/use-cases/address/GetAddressUseCase"; + +export const addressModuleFactory = () => + new ContainerModule(({ bind }) => { + bind(addressTypes.GetAddressUseCase).to(GetAddressUseCase); + }); diff --git a/packages/signer/signer-aleo/src/internal/use-cases/address/di/addressTypes.ts b/packages/signer/signer-aleo/src/internal/use-cases/address/di/addressTypes.ts new file mode 100644 index 000000000..671b42967 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/address/di/addressTypes.ts @@ -0,0 +1,3 @@ +export const addressTypes = { + GetAddressUseCase: Symbol.for("GetAddressUseCase"), +} as const; diff --git a/packages/signer/signer-aleo/src/internal/use-cases/config/GetAppConfigUseCase.ts b/packages/signer/signer-aleo/src/internal/use-cases/config/GetAppConfigUseCase.ts new file mode 100644 index 000000000..32e43794b --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/config/GetAppConfigUseCase.ts @@ -0,0 +1,22 @@ +import { inject, injectable } from "inversify"; + +import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; +import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; + +@injectable() +export class GetAppConfigUseCase { + private readonly _appBinder: AleoAppBinder; + + constructor( + @inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder, + ) { + this._appBinder = appBinder; + } + + execute(): GetAppConfigDAReturnType { + return this._appBinder.getAppConfig({ + skipOpenApp: false, + }); + } +} diff --git a/packages/signer/signer-aleo/src/internal/use-cases/config/di/configModule.ts b/packages/signer/signer-aleo/src/internal/use-cases/config/di/configModule.ts new file mode 100644 index 000000000..9ea31d222 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/config/di/configModule.ts @@ -0,0 +1,9 @@ +import { ContainerModule } from "inversify"; + +import { configTypes } from "@internal/use-cases/config/di/configTypes"; +import { GetAppConfigUseCase } from "@internal/use-cases/config/GetAppConfigUseCase"; + +export const configModuleFactory = () => + new ContainerModule(({ bind }) => { + bind(configTypes.GetAppConfigUseCase).to(GetAppConfigUseCase); + }); diff --git a/packages/signer/signer-aleo/src/internal/use-cases/config/di/configTypes.ts b/packages/signer/signer-aleo/src/internal/use-cases/config/di/configTypes.ts new file mode 100644 index 000000000..1f588c1fb --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/config/di/configTypes.ts @@ -0,0 +1,3 @@ +export const configTypes = { + GetAppConfigUseCase: Symbol.for("GetAppConfigUseCase"), +} as const; diff --git a/packages/signer/signer-aleo/src/internal/use-cases/message/SignMessageUseCase.ts b/packages/signer/signer-aleo/src/internal/use-cases/message/SignMessageUseCase.ts new file mode 100644 index 000000000..b58c4447b --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/message/SignMessageUseCase.ts @@ -0,0 +1,27 @@ +import { inject, injectable } from "inversify"; + +import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; +import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; + +@injectable() +export class SignMessageUseCase { + private readonly _appBinder: AleoAppBinder; + + constructor( + @inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder, + ) { + this._appBinder = appBinder; + } + + execute( + derivationPath: string, + message: string | Uint8Array, + ): SignMessageDAReturnType { + return this._appBinder.signMessage({ + derivationPath, + message, + skipOpenApp: false, + }); + } +} diff --git a/packages/signer/signer-aleo/src/internal/use-cases/message/di/messageModule.ts b/packages/signer/signer-aleo/src/internal/use-cases/message/di/messageModule.ts new file mode 100644 index 000000000..46de75518 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/message/di/messageModule.ts @@ -0,0 +1,9 @@ +import { ContainerModule } from "inversify"; + +import { messageTypes } from "@internal/use-cases/message/di/messageTypes"; +import { SignMessageUseCase } from "@internal/use-cases/message/SignMessageUseCase"; + +export const messageModuleFactory = () => + new ContainerModule(({ bind }) => { + bind(messageTypes.SignMessageUseCase).to(SignMessageUseCase); + }); diff --git a/packages/signer/signer-aleo/src/internal/use-cases/message/di/messageTypes.ts b/packages/signer/signer-aleo/src/internal/use-cases/message/di/messageTypes.ts new file mode 100644 index 000000000..04dc51d7b --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/message/di/messageTypes.ts @@ -0,0 +1,3 @@ +export const messageTypes = { + SignMessageUseCase: Symbol.for("SignMessageUseCase"), +} as const; diff --git a/packages/signer/signer-aleo/src/internal/use-cases/transaction/SignTransactionUseCase.ts b/packages/signer/signer-aleo/src/internal/use-cases/transaction/SignTransactionUseCase.ts new file mode 100644 index 000000000..79dd57393 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/transaction/SignTransactionUseCase.ts @@ -0,0 +1,29 @@ +import { inject, injectable } from "inversify"; + +import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; +import { type TransactionOptions } from "@api/model/TransactionOptions"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; +import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; + +@injectable() +export class SignTransactionUseCase { + private readonly _appBinder: AleoAppBinder; + + constructor( + @inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder, + ) { + this._appBinder = appBinder; + } + + execute( + derivationPath: string, + transaction: Uint8Array, + options?: TransactionOptions, + ): SignTransactionDAReturnType { + return this._appBinder.signTransaction({ + derivationPath, + transaction, + skipOpenApp: options?.skipOpenApp, + }); + } +} diff --git a/packages/signer/signer-aleo/src/internal/use-cases/transaction/di/transactionModule.ts b/packages/signer/signer-aleo/src/internal/use-cases/transaction/di/transactionModule.ts new file mode 100644 index 000000000..a749f88d8 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/transaction/di/transactionModule.ts @@ -0,0 +1,9 @@ +import { ContainerModule } from "inversify"; + +import { transactionTypes } from "@internal/use-cases/transaction/di/transactionTypes"; +import { SignTransactionUseCase } from "@internal/use-cases/transaction/SignTransactionUseCase"; + +export const transactionModuleFactory = () => + new ContainerModule(({ bind }) => { + bind(transactionTypes.SignTransactionUseCase).to(SignTransactionUseCase); + }); diff --git a/packages/signer/signer-aleo/src/internal/use-cases/transaction/di/transactionTypes.ts b/packages/signer/signer-aleo/src/internal/use-cases/transaction/di/transactionTypes.ts new file mode 100644 index 000000000..641d0e950 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/use-cases/transaction/di/transactionTypes.ts @@ -0,0 +1,3 @@ +export const transactionTypes = { + SignTransactionUseCase: Symbol.for("SignTransactionUseCase"), +} as const; diff --git a/packages/signer/signer-aleo/tsconfig.json b/packages/signer/signer-aleo/tsconfig.json new file mode 100644 index 000000000..d9a429203 --- /dev/null +++ b/packages/signer/signer-aleo/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "@ledgerhq/tsconfig-dsdk/tsconfig.sdk", + "compilerOptions": { + "baseUrl": ".", + "outDir": "./lib/types", + "module": "ES2022", + "target": "ES2022", + "moduleResolution": "bundler", + "emitDeclarationOnly": true, + "paths": { + "@api/*": ["./src/api/*"], + "@internal/*": ["./src/internal/*"], + "@root/*": ["./*"] + }, + "resolveJsonModule": true, + "types": ["vitest/globals", "node"] + }, + "include": ["src", "vitest.*.mjs"] +} diff --git a/packages/signer/signer-aleo/tsconfig.prod.json b/packages/signer/signer-aleo/tsconfig.prod.json new file mode 100644 index 000000000..b90fc83e0 --- /dev/null +++ b/packages/signer/signer-aleo/tsconfig.prod.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"] +} diff --git a/packages/signer/signer-aleo/vitest.config.mjs b/packages/signer/signer-aleo/vitest.config.mjs new file mode 100644 index 000000000..1dfc506bf --- /dev/null +++ b/packages/signer/signer-aleo/vitest.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; +import { vitestConfigDmk } from "@ledgerhq/vitest-config-dmk"; + +export default defineConfig({ + ...vitestConfigDmk, + test: { + ...vitestConfigDmk.test, + setupFiles: ["./vitest.setup.mjs"], + }, +}); diff --git a/packages/signer/signer-aleo/vitest.setup.mjs b/packages/signer/signer-aleo/vitest.setup.mjs new file mode 100644 index 000000000..fded23ac1 --- /dev/null +++ b/packages/signer/signer-aleo/vitest.setup.mjs @@ -0,0 +1 @@ +import "reflect-metadata"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f51d725c8..2b21989e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -877,6 +877,9 @@ importers: '@ledgerhq/device-mockserver-client': specifier: workspace:^ version: link:../../packages/mockserver-client + '@ledgerhq/device-signer-kit-aleo': + specifier: workspace:^ + version: link:../../packages/signer/signer-aleo '@ledgerhq/device-signer-kit-bitcoin': specifier: workspace:^ version: link:../../packages/signer/signer-btc @@ -1431,6 +1434,52 @@ importers: specifier: 'catalog:' version: 10.9.2(@types/node@24.3.0)(typescript@5.9.2) + packages/signer/signer-aleo: + dependencies: + '@ledgerhq/context-module': + specifier: workspace:^ + version: link:../context-module + '@ledgerhq/signer-utils': + specifier: workspace:^ + version: link:../signer-utils + inversify: + specifier: 'catalog:' + version: 7.5.1(reflect-metadata@0.2.2) + purify-ts: + specifier: 'catalog:' + version: 2.1.0 + reflect-metadata: + specifier: 'catalog:' + version: 0.2.2 + xstate: + specifier: 'catalog:' + version: 5.19.2 + devDependencies: + '@ledgerhq/device-management-kit': + specifier: workspace:^ + version: link:../../device-management-kit + '@ledgerhq/eslint-config-dsdk': + specifier: workspace:^ + version: link:../../config/eslint + '@ledgerhq/ldmk-tool': + specifier: workspace:^ + version: link:../../tools/ldmk-tool + '@ledgerhq/prettier-config-dsdk': + specifier: workspace:^ + version: link:../../config/prettier + '@ledgerhq/tsconfig-dsdk': + specifier: workspace:^ + version: link:../../config/typescript + '@ledgerhq/vitest-config-dmk': + specifier: workspace:^ + version: link:../../config/vitest + rxjs: + specifier: 'catalog:' + version: 7.8.2 + ts-node: + specifier: 'catalog:' + version: 10.9.2(@types/node@24.3.0)(typescript@5.9.2) + packages/signer/signer-btc: dependencies: '@types/crypto-js': From 2ded92390e11e1065c57dd15f24d6f09fb2baa2a Mon Sep 17 00:00:00 2001 From: Maciek Malik Date: Tue, 10 Feb 2026 14:45:57 +0100 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=9A=A8=20(signer-aleo):=20Fix=20linte?= =?UTF-8?q?r=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app-binder/command/GetAddressCommand.ts | 11 +++-------- .../app-binder/command/SignMessageCommand.ts | 11 +++-------- .../command/SignTransactionCommand.ts | 17 ++++++++--------- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAddressCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAddressCommand.ts index eb2a588fa..ab39763e5 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAddressCommand.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAddressCommand.ts @@ -30,19 +30,14 @@ export class GetAddressCommand } getApdu(): Apdu { - // TODO: Implement APDU construction based on your blockchain's protocol - // Example structure: - // const builder = new ApduBuilder({ cla: 0xe0, ins: 0x02, p1: 0x00, p2: 0x00 }); - // Add derivation path and other data to builder - // return builder.build(); - throw new Error("GetAddressCommand.getApdu() not implemented"); + throw new Error( + `GetAddressCommand.getApdu() not implemented (args: ${JSON.stringify(this.args)})`, + ); } parseResponse( _apduResponse: ApduResponse, ): CommandResult { - // TODO: Implement response parsing based on your blockchain's protocol - // return CommandResultFactory({ data: { ... } }); throw new Error("GetAddressCommand.parseResponse() not implemented"); } } diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts index d28c4e4af..9e120ec34 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts @@ -28,19 +28,14 @@ export class SignMessageCommand } getApdu(): Apdu { - // TODO: Implement APDU construction based on your blockchain's protocol - // Example structure: - // const builder = new ApduBuilder({ cla: 0xe0, ins: 0x02, p1: 0x00, p2: 0x00 }); - // Add derivation path and other data to builder - // return builder.build(); - throw new Error("SignMessageCommand.getApdu() not implemented"); + throw new Error( + `SignMessageCommand.getApdu() not implemented (args: ${JSON.stringify(this.args)})`, + ); } parseResponse( _apduResponse: ApduResponse, ): CommandResult { - // TODO: Implement response parsing based on your blockchain's protocol - // return CommandResultFactory({ data: { ... } }); throw new Error("SignMessageCommand.parseResponse() not implemented"); } } diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/SignTransactionCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/SignTransactionCommand.ts index a0047beca..0b5ad8b5f 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/SignTransactionCommand.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/SignTransactionCommand.ts @@ -22,7 +22,11 @@ export type SignTransactionCommandResponse = { export class SignTransactionCommand implements - Command + Command< + SignTransactionCommandResponse, + SignTransactionCommandArgs, + AleoErrorCodes + > { readonly name = "SignTransaction"; @@ -33,19 +37,14 @@ export class SignTransactionCommand } getApdu(): Apdu { - // TODO: Implement APDU construction based on your blockchain's protocol - // Example structure: - // const builder = new ApduBuilder({ cla: 0xe0, ins: 0x02, p1: 0x00, p2: 0x00 }); - // Add derivation path and other data to builder - // return builder.build(); - throw new Error("SignTransactionCommand.getApdu() not implemented"); + throw new Error( + `SignTransactionCommand.getApdu() not implemented (args: ${JSON.stringify(this.args)})`, + ); } parseResponse( _apduResponse: ApduResponse, ): CommandResult { - // TODO: Implement response parsing based on your blockchain's protocol - // return CommandResultFactory({ data: { ... } }); throw new Error("SignTransactionCommand.parseResponse() not implemented"); } } From ab9491c3b6481d3b1e0982eeda0b120d19be622c Mon Sep 17 00:00:00 2001 From: Maciek Malik Date: Tue, 10 Feb 2026 15:00:57 +0100 Subject: [PATCH 3/6] =?UTF-8?q?=E2=9C=A8=20(signer-aleo):=20Add=20get=20ap?= =?UTF-8?q?p=20config=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app-binder/command/GetAppConfigCommand.ts | 70 ++++++++++++++----- .../command/utils/aleoApplicationErrors.ts | 54 ++++++++++++-- 2 files changed, 101 insertions(+), 23 deletions(-) diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts index 6c8b0ac52..f8a1f13ed 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts @@ -1,40 +1,74 @@ import { type Apdu, + ApduBuilder, + type ApduBuilderArgs, + ApduParser, type ApduResponse, type Command, type CommandResult, + CommandResultFactory, + InvalidStatusWordError, } from "@ledgerhq/device-management-kit"; +import { CommandErrorHelper } from "@ledgerhq/signer-utils"; +import { Maybe } from "purify-ts"; -import { type AleoErrorCodes } from "./utils/aleoApplicationErrors"; +import { + ALEO_APP_ERRORS, + AleoAppCommandErrorFactory, + type AleoErrorCodes, +} from "./utils/aleoApplicationErrors"; export type GetAppConfigCommandResponse = { - // Define your app configuration response fields here - // Example: - // version: string; - // flags: number; + readonly version: string; }; +const EXPECTED_DATA_LENGTH = 3; + export class GetAppConfigCommand - implements - Command + implements Command { readonly name = "GetAppConfig"; - + private readonly errorHelper = new CommandErrorHelper< + GetAppConfigCommandResponse, + AleoErrorCodes + >(ALEO_APP_ERRORS, AleoAppCommandErrorFactory); getApdu(): Apdu { - // TODO: Implement APDU construction based on your blockchain's protocol - // Example structure: - // const builder = new ApduBuilder({ cla: 0xe0, ins: 0x02, p1: 0x00, p2: 0x00 }); - // Add derivation path and other data to builder - // return builder.build(); - throw new Error("GetAppConfigCommand.getApdu() not implemented"); + const getEthConfigArgs: ApduBuilderArgs = { + cla: 0xe0, + ins: 0x03, + p1: 0x00, + p2: 0x00, + }; + const builder = new ApduBuilder(getEthConfigArgs); + return builder.build(); } parseResponse( - _apduResponse: ApduResponse, + response: ApduResponse, ): CommandResult { - // TODO: Implement response parsing based on your blockchain's protocol - // return CommandResultFactory({ data: { ... } }); - throw new Error("GetAppConfigCommand.parseResponse() not implemented"); + return Maybe.fromNullable( + this.errorHelper.getError(response), + ).orDefaultLazy(() => { + const parser = new ApduParser(response); + const buffer = parser.extractFieldByLength(EXPECTED_DATA_LENGTH); + if ( + !buffer || + buffer.length !== EXPECTED_DATA_LENGTH || + buffer.some((element) => element === undefined) + ) { + return CommandResultFactory({ + error: new InvalidStatusWordError("Invalid response"), + }); + } + + const config: GetAppConfigCommandResponse = { + version: `${buffer[0]}.${buffer[1]}.${buffer[2]}`, + }; + + return CommandResultFactory({ + data: config, + }); + }); } } diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.ts index c7261ee54..acc425277 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.ts @@ -1,6 +1,50 @@ -export enum AleoErrorCodes { - // Define your error codes here - // Example: - // INVALID_DERIVATION_PATH = 0x6a80, - // TRANSACTION_PARSING_ERROR = 0x6a81, +import { + type CommandErrorArgs, + type CommandErrors, + DeviceExchangeError, +} from "@ledgerhq/device-management-kit"; + +export type AleoErrorCodes = + | "6985" + | "6a86" + | "6a87" + | "6d00" + | "6e00" + | "b000" + | "b001" + | "b002" + | "b003" + | "b004" + | "b005" + | "b006" + | "b007" + | "b008" + | "c000"; + +export const ALEO_APP_ERRORS: CommandErrors = { + "6985": { message: "Denied by user" }, + "6a86": { message: "Incorrect P1 or P2" }, + "6a87": { message: "Wrong LC or length of APDU command less than 5" }, + "6d00": { message: "Unknown command with this INS" }, + "6e00": { message: "Instruction class is different than CLA" }, + b000: { message: "Wrong response length (buffer too small or too big)" }, + b001: { message: "Fail to display BIP32 path" }, + b002: { message: "Fail to display address" }, + b003: { message: "Fail to display amount" }, + b004: { message: "Wrong transaction length" }, + b005: { message: "Fail of transaction parsing" }, + b006: { message: "Fail of transaction hash" }, + b007: { message: "Bad state" }, + b008: { message: "Signature fail" }, + c000: { message: "Swap failure" }, +}; + +export class AleoAppCommandError extends DeviceExchangeError { + constructor(args: CommandErrorArgs) { + super({ tag: "AleoAppCommandError", ...args }); + } } + +export const AleoAppCommandErrorFactory = ( + args: CommandErrorArgs, +) => new AleoAppCommandError(args); From a73ed735248409fe17469759ec5d2865216a9181 Mon Sep 17 00:00:00 2001 From: Maciek Malik Date: Wed, 11 Feb 2026 10:41:56 +0100 Subject: [PATCH 4/6] =?UTF-8?q?=E2=9C=85=20(signer-aleo):=20Add=20tests=20?= =?UTF-8?q?for=20the=20get=20app=20config=20and=20app=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../command/GetAppConfigCommand.test.ts | 73 +++++++++++++++ .../utils/aleoApplicationErrors.test.ts | 90 +++++++++++++++++++ packages/signer/signer-aleo/vitest.config.mjs | 19 +++- 3 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.test.ts create mode 100644 packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.test.ts diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.test.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.test.ts new file mode 100644 index 000000000..f77e70f68 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.test.ts @@ -0,0 +1,73 @@ +import { + ApduResponse, + CommandResultFactory, + isSuccessCommandResult, +} from "@ledgerhq/device-management-kit"; +import { GetAppConfigCommand } from "@internal/app-binder/command/GetAppConfigCommand"; + +const GET_APP_CONFIG_APDU = new Uint8Array([0xe0, 0x03, 0x00, 0x00, 0x00]); + +const GET_APP_CONFIG_RESPONSE_DATA = new Uint8Array([0x00, 0x01, 0x02]); + +const GET_APP_CONFIG_RESPONSE = new ApduResponse({ + statusCode: Uint8Array.from([0x90, 0x00]), + data: GET_APP_CONFIG_RESPONSE_DATA, +}); + +describe("GetAppConfigurationCommand", () => { + let command: GetAppConfigCommand; + + beforeEach(() => { + command = new GetAppConfigCommand(); + vi.clearAllMocks(); + vi.importActual("@ledgerhq/device-management-kit"); + }); + + describe("name", () => { + it("should be 'getAppConfiguration'", () => { + expect(command.name).toBe("GetAppConfig"); + }); + }); + + describe("getApdu", () => { + it("should return the correct APDU", () => { + const apdu = command.getApdu(); + expect(apdu.getRawApdu()).toEqual(GET_APP_CONFIG_APDU); + }); + }); + + describe("parseResponse", () => { + it("should parse the response correctly", () => { + const parsed = command.parseResponse(GET_APP_CONFIG_RESPONSE); + expect(parsed).toStrictEqual( + CommandResultFactory({ + data: { + version: "0.1.2", + }, + }), + ); + }); + + describe("error handling", () => { + it("should return error if response is not success", () => { + const response = new ApduResponse({ + statusCode: Uint8Array.from([0x6a, 0x86]), + data: new Uint8Array(0), + }); + const result = command.parseResponse(response); + expect(isSuccessCommandResult(result)).toBe(false); + if (!isSuccessCommandResult(result)) { + expect(result.error).toEqual( + expect.objectContaining({ + _tag: "AleoAppCommandError", + errorCode: "6a86", + message: "Incorrect P1 or P2", + }), + ); + } else { + assert.fail("Expected error"); + } + }); + }); + }); +}); diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.test.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.test.ts new file mode 100644 index 000000000..68c89ff70 --- /dev/null +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.test.ts @@ -0,0 +1,90 @@ +import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; +import { DeviceExchangeError } from "@ledgerhq/device-management-kit"; + +import { + ALEO_APP_ERRORS, + AleoAppCommandError, + AleoAppCommandErrorFactory, + type AleoErrorCodes, +} from "./aleoApplicationErrors"; + +describe("AleoAppCommandError", () => { + afterEach(() => { + vi.resetAllMocks(); + }); + + afterAll(() => { + vi.resetModules(); + }); + + it("should be an instance of DeviceExchangeError", () => { + const error = new AleoAppCommandError({ + message: "Test error message", + errorCode: "6985", + }); + + expect(error).toBeInstanceOf(DeviceExchangeError); + }); + + it("should set the correct message when provided", () => { + const customMessage = "Custom error message"; + const error = new AleoAppCommandError({ + message: customMessage, + errorCode: "6985", + }); + + expect(error.message).toBe(customMessage); + }); + + it("should set the correct customErrorCode", () => { + const errorCode: AleoErrorCodes = "6a86"; + const error = new AleoAppCommandError({ + message: "Incorrect P1 or P2", + errorCode, + }); + + expect(error.errorCode).toBe(errorCode); + }); + + it("should correlate error codes with messages from aleoApplicationErrors", () => { + const errorCode: AleoErrorCodes = "6e00"; + const expectedMessage = ALEO_APP_ERRORS[errorCode].message; + + const error = new AleoAppCommandError({ + message: expectedMessage, + errorCode, + }); + + expect(error.errorCode).toBe(errorCode); + expect(error.message).toBe(expectedMessage); + + expect(error).toBeInstanceOf(DeviceExchangeError); + }); + + it("should handle unknown error codes gracefully", () => { + const unknownErrorCode = "9999" as AleoErrorCodes; + const customMessage = "Unknown error occurred"; + + const error = new AleoAppCommandError({ + message: customMessage, + errorCode: unknownErrorCode, + }); + + expect(error.errorCode).toBe(unknownErrorCode); + expect(error.message).toBe(customMessage); + expect(error).toBeInstanceOf(DeviceExchangeError); + }); + + describe("AleoAppCommandErrorFactory", () => { + it("should create an instance of AleoAppCommandError", () => { + const error = AleoAppCommandErrorFactory({ + message: "Test error message", + errorCode: "6985", + }); + + expect(error).toBeInstanceOf(AleoAppCommandError); + expect(error.message).toBe("Test error message"); + expect(error.errorCode).toBe("6985"); + }); + }); +}); diff --git a/packages/signer/signer-aleo/vitest.config.mjs b/packages/signer/signer-aleo/vitest.config.mjs index 1dfc506bf..45f86746d 100644 --- a/packages/signer/signer-aleo/vitest.config.mjs +++ b/packages/signer/signer-aleo/vitest.config.mjs @@ -1,10 +1,23 @@ import { defineConfig } from "vitest/config"; -import { vitestConfigDmk } from "@ledgerhq/vitest-config-dmk"; +import baseConfig from "@ledgerhq/vitest-config-dmk"; +import path from "path"; export default defineConfig({ - ...vitestConfigDmk, + ...baseConfig, test: { - ...vitestConfigDmk.test, + ...baseConfig.test, + include: ["src/**/*.test.ts"], setupFiles: ["./vitest.setup.mjs"], + coverage: { + provider: "istanbul", + reporter: ["lcov", "text"], + include: ["src/**/*.ts"], + exclude: ["src/**/*.stub.ts", "src/index.ts", "src/api/index.ts"], + }, + }, + resolve: { + alias: { + "@internal": path.resolve(__dirname, "src/internal"), + }, }, }); From c2188c59a87774a03f3dfba008f9ded2356db070 Mon Sep 17 00:00:00 2001 From: Maciek Malik Date: Wed, 11 Feb 2026 10:47:22 +0100 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=93=9D=20(aleo-signer):=20Add=20chang?= =?UTF-8?q?elog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/fine-colts-battle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fine-colts-battle.md diff --git a/.changeset/fine-colts-battle.md b/.changeset/fine-colts-battle.md new file mode 100644 index 000000000..4b5947524 --- /dev/null +++ b/.changeset/fine-colts-battle.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/device-signer-kit-aleo": minor +--- + +Add aleo-signer module with get app config command support From 2510d9374f4c137e6d29156dd9a0646acc9b6a01 Mon Sep 17 00:00:00 2001 From: Maciek Malik Date: Wed, 11 Feb 2026 12:08:41 +0100 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=9A=A8=20(aleo-signer):=20Fix=20linte?= =?UTF-8?q?r=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/docs/references/signers/aleo.mdx | 5 +-- .../src/components/SignerAleoView/index.tsx | 36 ++++--------------- packages/signer/signer-aleo/CHANGELOG.md | 1 + packages/signer/signer-aleo/README.md | 2 +- packages/signer/signer-aleo/eslint.config.mjs | 14 ++++++-- .../signer/signer-aleo/src/api/SignerAleo.ts | 6 ++-- .../app-binder/GetAddressDeviceActionTypes.ts | 3 +- .../GetAppConfigDeviceActionTypes.ts | 8 ++--- .../SignMessageDeviceActionTypes.ts | 3 +- packages/signer/signer-aleo/src/api/index.ts | 15 ++++++++ .../signer-aleo/src/api/model/AppConfig.ts | 5 +-- .../src/internal/DefaultSignerAleo.ts | 21 +++++------ .../src/internal/app-binder/AleoAppBinder.ts | 17 +++++---- .../command/GetAppConfigCommand.test.ts | 1 + .../app-binder/command/GetAppConfigCommand.ts | 14 ++++---- .../app-binder/command/SignMessageCommand.ts | 1 + .../utils/aleoApplicationErrors.test.ts | 2 +- .../internal/app-binder/di/appBinderModule.ts | 2 +- .../signer/signer-aleo/src/internal/di.ts | 5 +-- .../use-cases/address/GetAddressUseCase.ts | 6 ++-- .../use-cases/config/GetAppConfigUseCase.ts | 6 ++-- .../use-cases/message/SignMessageUseCase.ts | 6 ++-- .../transaction/SignTransactionUseCase.ts | 6 ++-- 23 files changed, 88 insertions(+), 97 deletions(-) diff --git a/apps/docs/pages/docs/references/signers/aleo.mdx b/apps/docs/pages/docs/references/signers/aleo.mdx index 3366831b2..48cd85460 100644 --- a/apps/docs/pages/docs/references/signers/aleo.mdx +++ b/apps/docs/pages/docs/references/signers/aleo.mdx @@ -179,10 +179,7 @@ type Signature = { This method allows users to sign a text string that is displayed on Ledger devices. ```typescript -const { observable, cancel } = signerAleo.signMessage( - derivationPath, - message, -); +const { observable, cancel } = signerAleo.signMessage(derivationPath, message); ``` #### **Parameters** diff --git a/apps/sample/src/components/SignerAleoView/index.tsx b/apps/sample/src/components/SignerAleoView/index.tsx index 3e0bf7505..3bb806fd8 100644 --- a/apps/sample/src/components/SignerAleoView/index.tsx +++ b/apps/sample/src/components/SignerAleoView/index.tsx @@ -6,9 +6,6 @@ import { type GetAppConfigDAError, type GetAppConfigDAIntermediateValue, type GetAppConfigDAOutput, - type SignMessageDAError, - type SignMessageDAIntermediateValue, - type SignMessageDAOutput, type SignTransactionDAError, type SignTransactionDAIntermediateValue, type SignTransactionDAOutput, @@ -52,7 +49,11 @@ export const SignerAleoView: React.FC<{ sessionId: string }> = ({ { title: "Get Address", description: "Get an address from the device", - executeDeviceAction: ({ derivationPath, checkOnDevice, skipOpenApp }) => { + executeDeviceAction: ({ + derivationPath, + checkOnDevice, + skipOpenApp, + }) => { if (!signer) { throw new Error("Signer not initialized"); } @@ -90,12 +91,12 @@ export const SignerAleoView: React.FC<{ sessionId: string }> = ({ transaction .slice(2) .match(/.{1,2}/g) - ?.map((byte) => parseInt(byte, 16)) ?? [] + ?.map((byte) => parseInt(byte, 16)) ?? [], ) : new Uint8Array( transaction .match(/.{1,2}/g) - ?.map((byte) => parseInt(byte, 16)) ?? [] + ?.map((byte) => parseInt(byte, 16)) ?? [], ); return signer.signTransaction(derivationPath, txBytes, { skipOpenApp, @@ -117,29 +118,6 @@ export const SignerAleoView: React.FC<{ sessionId: string }> = ({ SignTransactionDAError, SignTransactionDAIntermediateValue >, - { - title: "Sign Message", - description: "Sign a message with the device", - executeDeviceAction: ({ derivationPath, message }) => { - if (!signer) { - throw new Error("Signer not initialized"); - } - return signer.signMessage(derivationPath, message); - }, - initialValues: { - derivationPath: "44'/0'/0'/0/0", - message: "Hello World", - }, - deviceModelId, - } satisfies DeviceActionProps< - SignMessageDAOutput, - { - derivationPath: string; - message: string; - }, - SignMessageDAError, - SignMessageDAIntermediateValue - >, ], [deviceModelId, signer], ); diff --git a/packages/signer/signer-aleo/CHANGELOG.md b/packages/signer/signer-aleo/CHANGELOG.md index c6c135965..a713356b9 100644 --- a/packages/signer/signer-aleo/CHANGELOG.md +++ b/packages/signer/signer-aleo/CHANGELOG.md @@ -5,4 +5,5 @@ All notable changes to this project will be documented in this file. ## [0.1.0] - 2026-02-05 ### Added + - Initial signer implementation for aleo diff --git a/packages/signer/signer-aleo/README.md b/packages/signer/signer-aleo/README.md index 7b0521654..db9d16bab 100644 --- a/packages/signer/signer-aleo/README.md +++ b/packages/signer/signer-aleo/README.md @@ -21,7 +21,7 @@ const address = await signer.getAddress("m/44'/0'/0'/0/0"); // Sign transaction const signature = await signer.signTransaction( "m/44'/0'/0'/0/0", - transactionBytes + transactionBytes, ); ``` diff --git a/packages/signer/signer-aleo/eslint.config.mjs b/packages/signer/signer-aleo/eslint.config.mjs index 0da70bba7..40734f180 100644 --- a/packages/signer/signer-aleo/eslint.config.mjs +++ b/packages/signer/signer-aleo/eslint.config.mjs @@ -1,3 +1,13 @@ -import { eslintConfigDmk } from "@ledgerhq/eslint-config-dsdk"; +import config from "@ledgerhq/eslint-config-dsdk"; -export default eslintConfigDmk; +export default [ + ...config, + { + ignores: ["eslint.config.mjs", "lib", "vitest.*.mjs"], + languageOptions: { + parserOptions: { + project: "./tsconfig.json", + }, + }, + }, +]; diff --git a/packages/signer/signer-aleo/src/api/SignerAleo.ts b/packages/signer/signer-aleo/src/api/SignerAleo.ts index d3c7b5d4e..13228dccb 100644 --- a/packages/signer/signer-aleo/src/api/SignerAleo.ts +++ b/packages/signer/signer-aleo/src/api/SignerAleo.ts @@ -1,9 +1,9 @@ -import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceActionTypes"; -import { type AddressOptions } from "@api/model/AddressOptions"; +import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; +import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; +import { type AddressOptions } from "@api/model/AddressOptions"; import { type TransactionOptions } from "@api/model/TransactionOptions"; -import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; export interface SignerAleo { getAppConfig: () => GetAppConfigDAReturnType; diff --git a/packages/signer/signer-aleo/src/api/app-binder/GetAddressDeviceActionTypes.ts b/packages/signer/signer-aleo/src/api/app-binder/GetAddressDeviceActionTypes.ts index 81d31cc76..34a4acbf7 100644 --- a/packages/signer/signer-aleo/src/api/app-binder/GetAddressDeviceActionTypes.ts +++ b/packages/signer/signer-aleo/src/api/app-binder/GetAddressDeviceActionTypes.ts @@ -11,7 +11,8 @@ import { type GetAddressCommandResponse } from "@internal/app-binder/command/Get import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors"; type GetAddressDAUserInteractionRequired = - | UserInteractionRequired.None | UserInteractionRequired.VerifyAddress; + | UserInteractionRequired.None + | UserInteractionRequired.VerifyAddress; export type GetAddressDAOutput = SendCommandInAppDAOutput; diff --git a/packages/signer/signer-aleo/src/api/app-binder/GetAppConfigDeviceActionTypes.ts b/packages/signer/signer-aleo/src/api/app-binder/GetAppConfigDeviceActionTypes.ts index f4b9f0bfa..31a72d9e2 100644 --- a/packages/signer/signer-aleo/src/api/app-binder/GetAppConfigDeviceActionTypes.ts +++ b/packages/signer/signer-aleo/src/api/app-binder/GetAppConfigDeviceActionTypes.ts @@ -7,14 +7,12 @@ import { type UserInteractionRequired, } from "@ledgerhq/device-management-kit"; -import { type GetAppConfigCommandResponse } from "@internal/app-binder/command/GetAppConfigCommand"; +import type { AppConfig } from "@api/model/AppConfig"; import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors"; -type GetAppConfigDAUserInteractionRequired = - | UserInteractionRequired.None; +type GetAppConfigDAUserInteractionRequired = UserInteractionRequired.None; -export type GetAppConfigDAOutput = - SendCommandInAppDAOutput; +export type GetAppConfigDAOutput = SendCommandInAppDAOutput; export type GetAppConfigDAError = | OpenAppDAError diff --git a/packages/signer/signer-aleo/src/api/app-binder/SignMessageDeviceActionTypes.ts b/packages/signer/signer-aleo/src/api/app-binder/SignMessageDeviceActionTypes.ts index ed93ad5d5..896d136b4 100644 --- a/packages/signer/signer-aleo/src/api/app-binder/SignMessageDeviceActionTypes.ts +++ b/packages/signer/signer-aleo/src/api/app-binder/SignMessageDeviceActionTypes.ts @@ -11,7 +11,8 @@ import { type SignMessageCommandResponse } from "@internal/app-binder/command/Si import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors"; type SignMessageDAUserInteractionRequired = - | UserInteractionRequired.None | UserInteractionRequired.SignPersonalMessage; + | UserInteractionRequired.None + | UserInteractionRequired.SignPersonalMessage; export type SignMessageDAOutput = SendCommandInAppDAOutput; diff --git a/packages/signer/signer-aleo/src/api/index.ts b/packages/signer/signer-aleo/src/api/index.ts index 16a927682..8f0dfd6aa 100644 --- a/packages/signer/signer-aleo/src/api/index.ts +++ b/packages/signer/signer-aleo/src/api/index.ts @@ -1,3 +1,18 @@ +export type { + GetAddressDAError, + GetAddressDAIntermediateValue, + GetAddressDAOutput, +} from "@api/app-binder/GetAddressDeviceActionTypes"; +export type { + GetAppConfigDAError, + GetAppConfigDAIntermediateValue, + GetAppConfigDAOutput, +} from "@api/app-binder/GetAppConfigDeviceActionTypes"; +export type { + SignTransactionDAError, + SignTransactionDAIntermediateValue, + SignTransactionDAOutput, +} from "@api/app-binder/SignTransactionDeviceActionTypes"; export * from "@api/SignerAleo"; export * from "@api/SignerAleoBuilder"; // Export other types as needed diff --git a/packages/signer/signer-aleo/src/api/model/AppConfig.ts b/packages/signer/signer-aleo/src/api/model/AppConfig.ts index ed4ad517b..b7b6799f7 100644 --- a/packages/signer/signer-aleo/src/api/model/AppConfig.ts +++ b/packages/signer/signer-aleo/src/api/model/AppConfig.ts @@ -1,6 +1,3 @@ export type AppConfig = { - // Define your app configuration fields here - // Example: - // version: string; - // flags: number; + version: string; }; diff --git a/packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts b/packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts index 4265ce9ea..f983c4be3 100644 --- a/packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts +++ b/packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts @@ -3,22 +3,23 @@ import { type DeviceSessionId, } from "@ledgerhq/device-management-kit"; import { type Container } from "inversify"; -import { type SignerAleo } from "@api/SignerAleo"; -import { makeContainer } from "@internal/di"; -import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; -import { configTypes } from "@internal/use-cases/config/di/configTypes"; -import { type GetAppConfigUseCase } from "@internal/use-cases/config/GetAppConfigUseCase"; + import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceActionTypes"; +import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; +import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; +import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; import { type AddressOptions } from "@api/model/AddressOptions"; +import { type TransactionOptions } from "@api/model/TransactionOptions"; +import { type SignerAleo } from "@api/SignerAleo"; +import { makeContainer } from "@internal/di"; import { addressTypes } from "@internal/use-cases/address/di/addressTypes"; import { type GetAddressUseCase } from "@internal/use-cases/address/GetAddressUseCase"; -import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; -import { type TransactionOptions } from "@api/model/TransactionOptions"; -import { transactionTypes } from "@internal/use-cases/transaction/di/transactionTypes"; -import { type SignTransactionUseCase } from "@internal/use-cases/transaction/SignTransactionUseCase"; -import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; +import { configTypes } from "@internal/use-cases/config/di/configTypes"; +import { type GetAppConfigUseCase } from "@internal/use-cases/config/GetAppConfigUseCase"; import { messageTypes } from "@internal/use-cases/message/di/messageTypes"; import { type SignMessageUseCase } from "@internal/use-cases/message/SignMessageUseCase"; +import { transactionTypes } from "@internal/use-cases/transaction/di/transactionTypes"; +import { type SignTransactionUseCase } from "@internal/use-cases/transaction/SignTransactionUseCase"; type DefaultSignerAleoConstructorArgs = { dmk: DeviceManagementKit; diff --git a/packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts b/packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts index 5958cfe51..70ed2ef5f 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts @@ -1,21 +1,22 @@ import { + CallTaskInAppDeviceAction, type DeviceManagementKit, type DeviceSessionId, SendCommandInAppDeviceAction, - CallTaskInAppDeviceAction, UserInteractionRequired, } from "@ledgerhq/device-management-kit"; import { inject, injectable } from "inversify"; -import { externalTypes } from "@internal/externalTypes"; -import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; + import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceActionTypes"; -import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; +import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; +import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; +import { externalTypes } from "@internal/externalTypes"; -import { GetAppConfigCommand } from "./command/GetAppConfigCommand"; import { GetAddressCommand } from "./command/GetAddressCommand"; -import { SignTransactionTask } from "./task/SignTransactionTask"; +import { GetAppConfigCommand } from "./command/GetAppConfigCommand"; import { SignMessageCommand } from "./command/SignMessageCommand"; +import { SignTransactionTask } from "./task/SignTransactionTask"; @injectable() export class AleoAppBinder { @@ -24,9 +25,7 @@ export class AleoAppBinder { @inject(externalTypes.SessionId) private sessionId: DeviceSessionId, ) {} - getAppConfig(args: { - skipOpenApp: boolean; - }): GetAppConfigDAReturnType { + getAppConfig(args: { skipOpenApp: boolean }): GetAppConfigDAReturnType { return this.dmk.executeDeviceAction({ sessionId: this.sessionId, deviceAction: new SendCommandInAppDeviceAction({ diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.test.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.test.ts index f77e70f68..061892121 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.test.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.test.ts @@ -3,6 +3,7 @@ import { CommandResultFactory, isSuccessCommandResult, } from "@ledgerhq/device-management-kit"; + import { GetAppConfigCommand } from "@internal/app-binder/command/GetAppConfigCommand"; const GET_APP_CONFIG_APDU = new Uint8Array([0xe0, 0x03, 0x00, 0x00, 0x00]); diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts index f8a1f13ed..8c9138aaf 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/GetAppConfigCommand.ts @@ -12,24 +12,22 @@ import { import { CommandErrorHelper } from "@ledgerhq/signer-utils"; import { Maybe } from "purify-ts"; +import { type AppConfig } from "@api/model/AppConfig"; + import { ALEO_APP_ERRORS, AleoAppCommandErrorFactory, type AleoErrorCodes, } from "./utils/aleoApplicationErrors"; -export type GetAppConfigCommandResponse = { - readonly version: string; -}; - const EXPECTED_DATA_LENGTH = 3; export class GetAppConfigCommand - implements Command + implements Command { readonly name = "GetAppConfig"; private readonly errorHelper = new CommandErrorHelper< - GetAppConfigCommandResponse, + AppConfig, AleoErrorCodes >(ALEO_APP_ERRORS, AleoAppCommandErrorFactory); @@ -46,7 +44,7 @@ export class GetAppConfigCommand parseResponse( response: ApduResponse, - ): CommandResult { + ): CommandResult { return Maybe.fromNullable( this.errorHelper.getError(response), ).orDefaultLazy(() => { @@ -62,7 +60,7 @@ export class GetAppConfigCommand }); } - const config: GetAppConfigCommandResponse = { + const config: AppConfig = { version: `${buffer[0]}.${buffer[1]}.${buffer[2]}`, }; diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts index 9e120ec34..a9b86e0b4 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/SignMessageCommand.ts @@ -6,6 +6,7 @@ import { } from "@ledgerhq/device-management-kit"; import { type Signature } from "@api/model/Signature"; + import { type AleoErrorCodes } from "./utils/aleoApplicationErrors"; export type SignMessageCommandArgs = { diff --git a/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.test.ts b/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.test.ts index 68c89ff70..e6b9e23e5 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.test.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/command/utils/aleoApplicationErrors.test.ts @@ -1,5 +1,5 @@ -import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; import { DeviceExchangeError } from "@ledgerhq/device-management-kit"; +import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; import { ALEO_APP_ERRORS, diff --git a/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderModule.ts b/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderModule.ts index 8a8c6e884..66f0bc080 100644 --- a/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderModule.ts +++ b/packages/signer/signer-aleo/src/internal/app-binder/di/appBinderModule.ts @@ -1,7 +1,7 @@ import { ContainerModule } from "inversify"; -import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; export const appBindingModuleFactory = () => new ContainerModule(({ bind }) => { diff --git a/packages/signer/signer-aleo/src/internal/di.ts b/packages/signer/signer-aleo/src/internal/di.ts index d43a1e712..6e00e871f 100644 --- a/packages/signer/signer-aleo/src/internal/di.ts +++ b/packages/signer/signer-aleo/src/internal/di.ts @@ -3,12 +3,13 @@ import { type DeviceSessionId, } from "@ledgerhq/device-management-kit"; import { Container } from "inversify"; + import { appBindingModuleFactory } from "@internal/app-binder/di/appBinderModule"; import { externalTypes } from "@internal/externalTypes"; -import { configModuleFactory } from "@internal/use-cases/config/di/configModule"; import { addressModuleFactory } from "@internal/use-cases/address/di/addressModule"; -import { transactionModuleFactory } from "@internal/use-cases/transaction/di/transactionModule"; +import { configModuleFactory } from "@internal/use-cases/config/di/configModule"; import { messageModuleFactory } from "@internal/use-cases/message/di/messageModule"; +import { transactionModuleFactory } from "@internal/use-cases/transaction/di/transactionModule"; type MakeContainerProps = { dmk: DeviceManagementKit; diff --git a/packages/signer/signer-aleo/src/internal/use-cases/address/GetAddressUseCase.ts b/packages/signer/signer-aleo/src/internal/use-cases/address/GetAddressUseCase.ts index 3ef75420f..af32ca63e 100644 --- a/packages/signer/signer-aleo/src/internal/use-cases/address/GetAddressUseCase.ts +++ b/packages/signer/signer-aleo/src/internal/use-cases/address/GetAddressUseCase.ts @@ -2,16 +2,14 @@ import { inject, injectable } from "inversify"; import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceActionTypes"; import { type AddressOptions } from "@api/model/AddressOptions"; -import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; @injectable() export class GetAddressUseCase { private readonly _appBinder: AleoAppBinder; - constructor( - @inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder, - ) { + constructor(@inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder) { this._appBinder = appBinder; } diff --git a/packages/signer/signer-aleo/src/internal/use-cases/config/GetAppConfigUseCase.ts b/packages/signer/signer-aleo/src/internal/use-cases/config/GetAppConfigUseCase.ts index 32e43794b..8e75af790 100644 --- a/packages/signer/signer-aleo/src/internal/use-cases/config/GetAppConfigUseCase.ts +++ b/packages/signer/signer-aleo/src/internal/use-cases/config/GetAppConfigUseCase.ts @@ -1,16 +1,14 @@ import { inject, injectable } from "inversify"; import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes"; -import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; @injectable() export class GetAppConfigUseCase { private readonly _appBinder: AleoAppBinder; - constructor( - @inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder, - ) { + constructor(@inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder) { this._appBinder = appBinder; } diff --git a/packages/signer/signer-aleo/src/internal/use-cases/message/SignMessageUseCase.ts b/packages/signer/signer-aleo/src/internal/use-cases/message/SignMessageUseCase.ts index b58c4447b..fbe17f20a 100644 --- a/packages/signer/signer-aleo/src/internal/use-cases/message/SignMessageUseCase.ts +++ b/packages/signer/signer-aleo/src/internal/use-cases/message/SignMessageUseCase.ts @@ -1,16 +1,14 @@ import { inject, injectable } from "inversify"; import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes"; -import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; @injectable() export class SignMessageUseCase { private readonly _appBinder: AleoAppBinder; - constructor( - @inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder, - ) { + constructor(@inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder) { this._appBinder = appBinder; } diff --git a/packages/signer/signer-aleo/src/internal/use-cases/transaction/SignTransactionUseCase.ts b/packages/signer/signer-aleo/src/internal/use-cases/transaction/SignTransactionUseCase.ts index 79dd57393..7e81c1fb2 100644 --- a/packages/signer/signer-aleo/src/internal/use-cases/transaction/SignTransactionUseCase.ts +++ b/packages/signer/signer-aleo/src/internal/use-cases/transaction/SignTransactionUseCase.ts @@ -2,16 +2,14 @@ import { inject, injectable } from "inversify"; import { type SignTransactionDAReturnType } from "@api/app-binder/SignTransactionDeviceActionTypes"; import { type TransactionOptions } from "@api/model/TransactionOptions"; -import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; import { AleoAppBinder } from "@internal/app-binder/AleoAppBinder"; +import { appBinderTypes } from "@internal/app-binder/di/appBinderTypes"; @injectable() export class SignTransactionUseCase { private readonly _appBinder: AleoAppBinder; - constructor( - @inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder, - ) { + constructor(@inject(appBinderTypes.AppBinding) appBinder: AleoAppBinder) { this._appBinder = appBinder; }