Skip to content

Commit 2588664

Browse files
authored
πŸ”– (release) [NO-ISSUE]: New release incoming: DMK 1.4.0 (#1468)
2 parents 7e66412 + 9dfbbce commit 2588664

48 files changed

Lines changed: 2422 additions & 66 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@ledgerhq/device-management-kit-sample": minor
3+
---
4+
5+
Add Language Package install device action
6+
Add List and Delete Language Package commands
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ledgerhq/device-signer-kit-solana": minor
3+
---
4+
5+
Add additional signers input for solana signMessage v1
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ledgerhq/device-signer-kit-bitcoin": patch
3+
---
4+
5+
Always use protocol version 1 on all Bitcoin APDUs for consistency and to ease future upgrades

β€Žapps/docs/pages/docs/getting-started.mdxβ€Ž

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Here you can find a summary of all the libraries that compose the DMK.
3939

4040
| Device Management Kit (DMK) | NPM | Version |
4141
| --------------------------- | ------------------------------------------------------------------------------------------------ | ------- |
42-
| Device Management Kit | [@ledgerhq/device-management-kit](https://www.npmjs.com/package/@ledgerhq/device-management-kit) | 1.3.0 |
42+
| Device Management Kit | [@ledgerhq/device-management-kit](https://www.npmjs.com/package/@ledgerhq/device-management-kit) | 1.4.0 |
4343

4444
| Signers & Trusted App Kit | NPM | Version |
4545
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
@@ -70,3 +70,11 @@ Here you can find a summary of all the libraries that compose the DMK.
7070
| DevTools Websocket Common | [@ledgerhq/device-management-kit-devtools-websocket-common](https://www.npmjs.com/package/@ledgerhq/device-management-kit-devtools-websocket-common) | 1.0.2 |
7171
| DevTools Websocket Connector | [@ledgerhq/device-management-kit-devtools-websocket-connector](https://www.npmjs.com/package/@ledgerhq/device-management-kit-devtools-websocket-connector) | 1.1.1 |
7272
| DevTools Websocket Server | [@ledgerhq/device-management-kit-devtools-websocket-server](https://www.npmjs.com/package/@ledgerhq/device-management-kit-devtools-websocket-server) | 1.0.1 |
73+
74+
## Legal notice
75+
76+
The Device Management Kit (DMK) is made available under an open source license and is free to use for development, testing, and integration purposes.
77+
78+
Please note that access to the DMK does not grant you any rights to access Ledger SAS backend services, nor any rights to use tokens, APIs, or infrastructure beyond what is explicitly allowed under the open source license. Access to Ledger SAS backend is strictly prohibited unless explicitly authorized by Ledger SAS.
79+
80+
Use of any token to gain access to Ledger SAS backend without a formal, written legal agreement is forbidden. Unauthorized use or access may lead to legal claims, including but not limited to injunctive relief, damages, or other remedies permitted under applicable law.

β€Žapps/docs/pages/docs/references/signers/solana.mdxβ€Ž

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ Sign a Solana off-chain message on Ledger devices. Supports multiple signing
240240
modes via `SignMessageVersion`:
241241

242242
- **V0** (default) β€” original [off-chain message](https://docs.anza.xyz/proposals/off-chain-message-signing) header with `appDomain` and signer fields. Supported on all firmware with off-chain signing. Falls back to Legacy on `6a81`.
243-
- **V1** β€” simplified header without `appDomain`; supports lexicographically sorted multi-signer payloads. Requires Solana device app version 1.14+. Falls back to V0 then Legacy on `6a81`.
243+
- **V1** β€” simplified header per [sRFC 38](https://github.com/solana-foundation/SRFCs/discussions/3): no `appDomain`, no format byte. Use `signers` to bind the message to a specific application instead. Requires Solana device app version 1.14+. Falls back to V0 then Legacy on `6a81`.
244244
- **Legacy** β€” compact header for backward compatibility with very old Solana app firmware. Current firmware will reject it.
245245
- **Raw** β€” pass-through: the caller provides the fully formatted payload as a `Uint8Array` and the SDK sends it as-is with no header wrapping.
246246

@@ -279,6 +279,11 @@ const { observable, cancel } = signerSolana.signMessage(
279279
(UTF-8 encoded, padded/truncated to 32 bytes). Defaults to 32 zero bytes.
280280
Ignored for V1, Legacy, and Raw.
281281

282+
- **signers** `Uint8Array[]`
283+
V1 only: additional required signers to include in the off-chain message header alongside the user's key. Per sRFC 38, this is the recommended replacement for the V0 `appDomain` field β€” pass the dApp's public key here to bind the message to a specific application. Signers are sorted and deduplicated automatically.
284+
Each entry must be a 32-byte Ed25519 public key. At most 254 additional signers are supported (1 slot is reserved for the user's key). Passing a signer with the wrong length or exceeding the limit returns an error before any device communication.
285+
Ignored for V0, Legacy, and Raw.
286+
282287
- **skipOpenApp** `boolean`
283288
If `true`, skips opening the Solana app on the device.
284289

@@ -287,7 +292,8 @@ import { SignMessageVersion } from "@ledgerhq/device-signer-kit-solana";
287292

288293
type MessageOptions = {
289294
version?: SignMessageVersion;
290-
appDomain?: string;
295+
appDomain?: string; // V0 only
296+
signers?: Uint8Array[]; // V1 only
291297
skipOpenApp?: boolean;
292298
};
293299
```
@@ -324,11 +330,14 @@ type SignMessageDAOutput = {
324330
```typescript
325331
import { SignMessageVersion } from "@ledgerhq/device-signer-kit-solana";
326332

327-
// V0 (default) β€” sign a simple text message
333+
// V0 β€” sign with app domain
328334
const { observable } = signerSolana.signMessage(
329335
"44'/501'/0'/0'",
330336
"Hello World",
331-
{ version: SignMessageVersion.V0 },
337+
{
338+
version: SignMessageVersion.V0,
339+
appDomain: "my-app.com",
340+
},
332341
);
333342

334343
observable.subscribe({
@@ -350,6 +359,22 @@ observable.subscribe({
350359
});
351360
```
352361

362+
#### V1 with Additional Signers
363+
364+
V1 removes `appDomain` (no central registry β€” anyone could spoof it). To bind a message to a specific application, add the dApp's public key as a required signer instead:
365+
366+
```typescript
367+
// V1 β€” bind message to dApp via required signer (sRFC 38)
368+
const { observable } = signerSolana.signMessage(
369+
"44'/501'/0'/0'",
370+
"Hello World",
371+
{
372+
version: SignMessageVersion.V1,
373+
signers: [dAppPubkeyBytes], // dApp's Ed25519 public key as Uint8Array(32)
374+
},
375+
);
376+
```
377+
353378
#### Raw Mode
354379

355380
In Raw mode, the caller is responsible for constructing the full off-chain

β€Žapps/sample/package.jsonβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@ledgerhq/react-ui": "catalog:",
4242
"@ledgerhq/solana-tools": "workspace:^",
4343
"@noble/secp256k1": "^2.3.0",
44+
"bs58": "catalog:",
4445
"@playwright/test": "catalog:",
4546
"@reduxjs/toolkit": "catalog:",
4647
"@sentry/nextjs": "catalog:",

β€Žapps/sample/src/components/CommandsView/index.tsxβ€Ž

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import {
55
type BackupStorageCommandResponse,
66
BatteryStatusType,
77
CloseAppCommand,
8+
DeleteLanguagePackCommand,
9+
type DeleteLanguagePackCommandArgs,
10+
type DeleteLanguagePackErrorCodes,
811
GetAppAndVersionCommand,
912
type GetAppAndVersionResponse,
1013
GetAppStorageInfoCommand,
@@ -20,6 +23,10 @@ import {
2023
ListAppsCommand,
2124
type ListAppsErrorCodes,
2225
type ListAppsResponse,
26+
ListLanguagePackCommand,
27+
type ListLanguagePackCommandArgs,
28+
type ListLanguagePackErrorCodes,
29+
type ListLanguagePackResponse,
2330
type OpenAppArgs,
2431
OpenAppCommand,
2532
type OpenAppErrorCodes,
@@ -154,6 +161,40 @@ export const CommandsView: React.FC<{ sessionId: string }> = ({
154161
BackupStorageCommandResponse,
155162
BackupStorageCommandErrorCodes
156163
>,
164+
{
165+
title: "List language packs",
166+
description:
167+
"List installed language packages (first chunk or continue)",
168+
sendCommand: ({ firstChunk }) => {
169+
const command = new ListLanguagePackCommand({ firstChunk });
170+
return dmk.sendCommand({
171+
sessionId: selectedSessionId,
172+
command,
173+
});
174+
},
175+
initialValues: { firstChunk: true },
176+
} satisfies CommandProps<
177+
ListLanguagePackCommandArgs,
178+
ListLanguagePackResponse,
179+
ListLanguagePackErrorCodes
180+
>,
181+
{
182+
title: "Delete language pack",
183+
description:
184+
"Delete an installed language pack by id (use 255 / 0xFF to remove all)",
185+
sendCommand: ({ languagePackageId }) => {
186+
const command = new DeleteLanguagePackCommand({ languagePackageId });
187+
return dmk.sendCommand({
188+
sessionId: selectedSessionId,
189+
command,
190+
});
191+
},
192+
initialValues: { languagePackageId: 1 },
193+
} satisfies CommandProps<
194+
DeleteLanguagePackCommandArgs,
195+
void,
196+
DeleteLanguagePackErrorCodes
197+
>,
157198
],
158199
[selectedSessionId, dmk],
159200
);

β€Žapps/sample/src/components/DeviceActionsView/AllDeviceActions.tsxβ€Ž

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ import {
2626
type InstallAppDAIntermediateValue,
2727
type InstallAppDAOutput,
2828
InstallAppDeviceAction,
29+
type InstallLanguagePackageDAError,
30+
type InstallLanguagePackageDAInput,
31+
type InstallLanguagePackageDAIntermediateValue,
32+
type InstallLanguagePackageDAOutput,
33+
InstallLanguagePackageDeviceAction,
2934
type InstallOrUpdateAppsDAError,
3035
type InstallOrUpdateAppsDAIntermediateValue,
3136
type InstallOrUpdateAppsDAOutput,
@@ -203,6 +208,30 @@ export const AllDeviceActions: React.FC<{ sessionId: string }> = ({
203208
GoToDashboardDAError,
204209
GoToDashboardDAIntermediateValue
205210
>,
211+
{
212+
title: "Install language package",
213+
description: "Install the language package for the given language",
214+
executeDeviceAction: ({ unlockTimeout, language }, inspect) => {
215+
const deviceAction = new InstallLanguagePackageDeviceAction({
216+
input: { unlockTimeout, language },
217+
inspect,
218+
});
219+
return dmk.executeDeviceAction({
220+
sessionId,
221+
deviceAction,
222+
});
223+
},
224+
initialValues: {
225+
unlockTimeout: UNLOCK_TIMEOUT,
226+
language: "french",
227+
},
228+
deviceModelId,
229+
} satisfies DeviceActionProps<
230+
InstallLanguagePackageDAOutput,
231+
InstallLanguagePackageDAInput,
232+
InstallLanguagePackageDAError,
233+
InstallLanguagePackageDAIntermediateValue
234+
>,
206235
{
207236
title: "List apps",
208237
description: "List all applications installed on the device",

β€Žapps/sample/src/components/SignerSolanaView/index.tsxβ€Ž

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
type GenerateTransactionDAOutput,
3131
SolanaToolsBuilder,
3232
} from "@ledgerhq/solana-tools";
33+
import bs58 from "bs58";
3334

3435
import { DeviceActionsList } from "@/components/DeviceActionsView/DeviceActionsList";
3536
import { type DeviceActionProps } from "@/components/DeviceActionsView/DeviceActionTester";
@@ -254,6 +255,8 @@ export const SignerSolanaView: React.FC<{ sessionId: string }> = ({
254255
message,
255256
version,
256257
skipOpenApp,
258+
appDomain,
259+
signers,
257260
}) => {
258261
if (!signer) {
259262
throw new Error("Signer not initialized");
@@ -270,16 +273,31 @@ export const SignerSolanaView: React.FC<{ sessionId: string }> = ({
270273
hex.match(/.{1,2}/g)?.map((b) => parseInt(b, 16)) ?? [],
271274
);
272275
}
276+
const parsedSigners =
277+
version === SignMessageVersion.V1 && signers.trim()
278+
? signers
279+
.split(",")
280+
.map((s) => s.trim())
281+
.filter(Boolean)
282+
.map((s) => bs58.decode(s))
283+
: undefined;
273284
return signer.signMessage(derivationPath, payload, {
274285
version,
275286
skipOpenApp,
287+
appDomain:
288+
version === SignMessageVersion.V0 && appDomain
289+
? appDomain
290+
: undefined,
291+
signers: parsedSigners,
276292
});
277293
},
278294
initialValues: {
279295
derivationPath: DEFAULT_DERIVATION_PATH,
280296
message: "Hello World",
281297
version: SignMessageVersion.V0,
282298
skipOpenApp: false,
299+
appDomain: "",
300+
signers: "",
283301
},
284302
valueSelector: {
285303
version: signMessageVersionOptions,
@@ -289,6 +307,8 @@ export const SignerSolanaView: React.FC<{ sessionId: string }> = ({
289307
message: "Message (hex bytes for Raw mode)",
290308
version: "Signing mode",
291309
skipOpenApp: "Skip open app",
310+
appDomain: "App domain (V0 only)",
311+
signers: "Additional signers, comma-separated base58 (V1 only)",
292312
},
293313
deviceModelId,
294314
} satisfies DeviceActionProps<
@@ -298,6 +318,8 @@ export const SignerSolanaView: React.FC<{ sessionId: string }> = ({
298318
message: string;
299319
version: SignMessageVersion;
300320
skipOpenApp: boolean;
321+
appDomain: string;
322+
signers: string;
301323
},
302324
SignMessageDAError,
303325
SignMessageDAIntermediateValue

β€Žpackages/device-management-kit/CHANGELOG.mdβ€Ž

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# @ledgerhq/device-management-kit
22

3+
## 1.4.0
4+
5+
### Minor Changes
6+
7+
- [#1382](https://github.com/LedgerHQ/device-sdk-ts/pull/1382) [`68947bf`](https://github.com/LedgerHQ/device-sdk-ts/commit/68947bfa299c7c7620c7a3bf3de5788555ba4961) Thanks [@pvautherin-ledger](https://github.com/pvautherin-ledger)! - Add Language Package install device action and Delete command
8+
9+
### Patch Changes
10+
11+
- [#1467](https://github.com/LedgerHQ/device-sdk-ts/pull/1467) [`16e08f2`](https://github.com/LedgerHQ/device-sdk-ts/commit/16e08f2e504e5361f6a0e70de679ad588b5034b2) Thanks [@aussedatlo](https://github.com/aussedatlo)! - Fix React Native compatibility in `DmkNetworkClient`: serialize query params manually instead of using `URLSearchParams.set` (not implemented in React Native), and guard optional Web globals (`Blob`, `FormData`, `URLSearchParams`, `ReadableStream`) in `isRawBody` to avoid `ReferenceError` on runtimes where they are missing.
12+
13+
- [#1461](https://github.com/LedgerHQ/device-sdk-ts/pull/1461) [`8051f90`](https://github.com/LedgerHQ/device-sdk-ts/commit/8051f908e987c178e3e54aa5132d4111a354969d) Thanks [@fAnselmi-Ledger](https://github.com/fAnselmi-Ledger)! - Add InvalidArgumentError error
14+
315
## 1.3.0
416

517
### Minor Changes

0 commit comments

Comments
Β (0)