@ledgerhq/coin-tester 0.12.0 → 0.13.0-nightly.20251126160702
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/lib/signers/speculos.d.ts +2 -2
- package/lib/signers/speculos.d.ts.map +1 -1
- package/lib/signers/speculos.js +32 -15
- package/lib/signers/speculos.js.map +1 -1
- package/lib-es/signers/speculos.d.ts +2 -2
- package/lib-es/signers/speculos.d.ts.map +1 -1
- package/lib-es/signers/speculos.js +32 -15
- package/lib-es/signers/speculos.js.map +1 -1
- package/package.json +4 -3
- package/src/signers/speculos.ts +37 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @ledgerhq/coin-tester
|
|
2
2
|
|
|
3
|
+
## 0.13.0-nightly.20251126160702
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#12563](https://github.com/LedgerHQ/ledger-live/pull/12563) [`b4a4e16`](https://github.com/LedgerHQ/ledger-live/commit/b4a4e160aae6fd64f944ab25633f6931dc4358d3) Thanks [@fAnselmi-Ledger](https://github.com/fAnselmi-Ledger)! - Add DMK speculos transport and device controller
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`b4a4e16`](https://github.com/LedgerHQ/ledger-live/commit/b4a4e160aae6fd64f944ab25633f6931dc4358d3)]:
|
|
12
|
+
- @ledgerhq/live-dmk-speculos@0.2.0-nightly.20251126160702
|
|
13
|
+
|
|
3
14
|
## 0.12.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DeviceManagementKitTransportSpeculos } from "@ledgerhq/live-dmk-speculos";
|
|
2
2
|
export declare const delay: (timing: number) => Promise<unknown>;
|
|
3
3
|
export declare function ensureEnv(): void;
|
|
4
4
|
export declare function spawnSpeculos(nanoAppEndpoint: `/${string}`, options?: {
|
|
@@ -7,7 +7,7 @@ export declare function spawnSpeculos(nanoAppEndpoint: `/${string}`, options?: {
|
|
|
7
7
|
endpoint: `/${string}`;
|
|
8
8
|
}>;
|
|
9
9
|
}): Promise<{
|
|
10
|
-
transport:
|
|
10
|
+
transport: DeviceManagementKitTransportSpeculos;
|
|
11
11
|
getOnSpeculosConfirmation: (approvalText?: string) => () => Promise<void>;
|
|
12
12
|
}>;
|
|
13
13
|
export declare function killSpeculos(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speculos.d.ts","sourceRoot":"","sources":["../../src/signers/speculos.ts"],"names":[],"mappings":"AAMA,OAAO,
|
|
1
|
+
{"version":3,"file":"speculos.d.ts","sourceRoot":"","sources":["../../src/signers/speculos.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,oCAAoC,EAAE,MAAM,6BAA6B,CAAC;AAOnF,eAAO,MAAM,KAAK,WAAY,MAAM,qBAAwD,CAAC;AAE7F,wBAAgB,SAAS,SAexB;AAeD,wBAAsB,aAAa,CACjC,eAAe,EAAE,IAAI,MAAM,EAAE,EAC7B,OAAO,CAAC,EAAE;IACR,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CAC7D,GACA,OAAO,CAAC;IACT,SAAS,EAAE,oCAAoC,CAAC;IAChD,yBAAyB,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E,CAAC,CAmGD;AAED,wBAAsB,YAAY,kBAQjC"}
|
package/lib/signers/speculos.js
CHANGED
|
@@ -35,7 +35,8 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
35
35
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
36
36
|
const compose = __importStar(require("docker-compose"));
|
|
37
37
|
const axios_1 = __importStar(require("axios"));
|
|
38
|
-
const
|
|
38
|
+
const live_dmk_speculos_1 = require("@ledgerhq/live-dmk-speculos");
|
|
39
|
+
const speculos_device_controller_1 = require("@ledgerhq/speculos-device-controller");
|
|
39
40
|
const { SPECULOS_API_PORT } = process.env;
|
|
40
41
|
const cwd = path_1.default.join(__dirname);
|
|
41
42
|
const delay = (timing) => new Promise(resolve => setTimeout(resolve, timing));
|
|
@@ -98,7 +99,7 @@ async function spawnSpeculos(nanoAppEndpoint, options) {
|
|
|
98
99
|
const { out } = await compose.logs("speculos", { cwd, env: process.env });
|
|
99
100
|
if (out.includes("Server started")) {
|
|
100
101
|
console.log(chalk_1.default.bgYellowBright.black(" - SPECULOS READY ✅ - "));
|
|
101
|
-
return
|
|
102
|
+
return live_dmk_speculos_1.DeviceManagementKitTransportSpeculos.open({
|
|
102
103
|
apiPort: SPECULOS_API_PORT,
|
|
103
104
|
});
|
|
104
105
|
}
|
|
@@ -106,23 +107,39 @@ async function spawnSpeculos(nanoAppEndpoint, options) {
|
|
|
106
107
|
return checkSpeculosLogs();
|
|
107
108
|
}
|
|
108
109
|
function getOnSpeculosConfirmation(approvalText = "Accept") {
|
|
109
|
-
async function onSpeculosConfirmation(e) {
|
|
110
|
-
if (e?.type
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
return async function onSpeculosConfirmation(e) {
|
|
111
|
+
if (e?.type !== "device-signature-requested")
|
|
112
|
+
return;
|
|
113
|
+
const baseURL = `http://127.0.0.1:${SPECULOS_API_PORT}`;
|
|
114
|
+
const buttonClient = (0, speculos_device_controller_1.deviceControllerClientFactory)(baseURL).buttonFactory();
|
|
115
|
+
const maxAttempts = 80;
|
|
116
|
+
const delayMs = 250;
|
|
117
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
118
|
+
try {
|
|
119
|
+
const { data } = await axios_1.default.get(`${baseURL}/events?currentscreenonly=true`, {
|
|
120
|
+
timeout: 2000,
|
|
115
121
|
});
|
|
116
|
-
|
|
122
|
+
const text = data?.events?.[0]?.text;
|
|
123
|
+
if (text === approvalText) {
|
|
124
|
+
await buttonClient.both();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// not on the approval screen yet—scroll right and retry
|
|
128
|
+
await buttonClient.right();
|
|
117
129
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
130
|
+
catch (err) {
|
|
131
|
+
// retry on network issues
|
|
132
|
+
if (axios_1.default.isAxiosError(err)) {
|
|
133
|
+
// fall through to retry
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
122
138
|
}
|
|
139
|
+
await (0, exports.delay)(delayMs);
|
|
123
140
|
}
|
|
124
|
-
|
|
125
|
-
|
|
141
|
+
throw new Error(`Speculos confirmation not reached after ${maxAttempts} attempts`);
|
|
142
|
+
};
|
|
126
143
|
}
|
|
127
144
|
return checkSpeculosLogs().then(transport => {
|
|
128
145
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speculos.js","sourceRoot":"","sources":["../../src/signers/speculos.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"speculos.js","sourceRoot":"","sources":["../../src/signers/speculos.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DeviceManagementKitTransportSpeculos } from "@ledgerhq/live-dmk-speculos";
|
|
2
2
|
export declare const delay: (timing: number) => Promise<unknown>;
|
|
3
3
|
export declare function ensureEnv(): void;
|
|
4
4
|
export declare function spawnSpeculos(nanoAppEndpoint: `/${string}`, options?: {
|
|
@@ -7,7 +7,7 @@ export declare function spawnSpeculos(nanoAppEndpoint: `/${string}`, options?: {
|
|
|
7
7
|
endpoint: `/${string}`;
|
|
8
8
|
}>;
|
|
9
9
|
}): Promise<{
|
|
10
|
-
transport:
|
|
10
|
+
transport: DeviceManagementKitTransportSpeculos;
|
|
11
11
|
getOnSpeculosConfirmation: (approvalText?: string) => () => Promise<void>;
|
|
12
12
|
}>;
|
|
13
13
|
export declare function killSpeculos(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speculos.d.ts","sourceRoot":"","sources":["../../src/signers/speculos.ts"],"names":[],"mappings":"AAMA,OAAO,
|
|
1
|
+
{"version":3,"file":"speculos.d.ts","sourceRoot":"","sources":["../../src/signers/speculos.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,oCAAoC,EAAE,MAAM,6BAA6B,CAAC;AAOnF,eAAO,MAAM,KAAK,WAAY,MAAM,qBAAwD,CAAC;AAE7F,wBAAgB,SAAS,SAexB;AAeD,wBAAsB,aAAa,CACjC,eAAe,EAAE,IAAI,MAAM,EAAE,EAC7B,OAAO,CAAC,EAAE;IACR,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CAC7D,GACA,OAAO,CAAC;IACT,SAAS,EAAE,oCAAoC,CAAC;IAChD,yBAAyB,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E,CAAC,CAmGD;AAED,wBAAsB,YAAY,kBAQjC"}
|
|
@@ -3,7 +3,8 @@ import chalk from "chalk";
|
|
|
3
3
|
import fs from "fs/promises";
|
|
4
4
|
import * as compose from "docker-compose";
|
|
5
5
|
import axios, { AxiosError } from "axios";
|
|
6
|
-
import
|
|
6
|
+
import { DeviceManagementKitTransportSpeculos } from "@ledgerhq/live-dmk-speculos";
|
|
7
|
+
import { deviceControllerClientFactory } from "@ledgerhq/speculos-device-controller";
|
|
7
8
|
const { SPECULOS_API_PORT } = process.env;
|
|
8
9
|
const cwd = path.join(__dirname);
|
|
9
10
|
export const delay = (timing) => new Promise(resolve => setTimeout(resolve, timing));
|
|
@@ -65,7 +66,7 @@ export async function spawnSpeculos(nanoAppEndpoint, options) {
|
|
|
65
66
|
const { out } = await compose.logs("speculos", { cwd, env: process.env });
|
|
66
67
|
if (out.includes("Server started")) {
|
|
67
68
|
console.log(chalk.bgYellowBright.black(" - SPECULOS READY ✅ - "));
|
|
68
|
-
return
|
|
69
|
+
return DeviceManagementKitTransportSpeculos.open({
|
|
69
70
|
apiPort: SPECULOS_API_PORT,
|
|
70
71
|
});
|
|
71
72
|
}
|
|
@@ -73,23 +74,39 @@ export async function spawnSpeculos(nanoAppEndpoint, options) {
|
|
|
73
74
|
return checkSpeculosLogs();
|
|
74
75
|
}
|
|
75
76
|
function getOnSpeculosConfirmation(approvalText = "Accept") {
|
|
76
|
-
async function onSpeculosConfirmation(e) {
|
|
77
|
-
if (e?.type
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
return async function onSpeculosConfirmation(e) {
|
|
78
|
+
if (e?.type !== "device-signature-requested")
|
|
79
|
+
return;
|
|
80
|
+
const baseURL = `http://127.0.0.1:${SPECULOS_API_PORT}`;
|
|
81
|
+
const buttonClient = deviceControllerClientFactory(baseURL).buttonFactory();
|
|
82
|
+
const maxAttempts = 80;
|
|
83
|
+
const delayMs = 250;
|
|
84
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
85
|
+
try {
|
|
86
|
+
const { data } = await axios.get(`${baseURL}/events?currentscreenonly=true`, {
|
|
87
|
+
timeout: 2000,
|
|
82
88
|
});
|
|
83
|
-
|
|
89
|
+
const text = data?.events?.[0]?.text;
|
|
90
|
+
if (text === approvalText) {
|
|
91
|
+
await buttonClient.both();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// not on the approval screen yet—scroll right and retry
|
|
95
|
+
await buttonClient.right();
|
|
84
96
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
catch (err) {
|
|
98
|
+
// retry on network issues
|
|
99
|
+
if (axios.isAxiosError(err)) {
|
|
100
|
+
// fall through to retry
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw err;
|
|
104
|
+
}
|
|
89
105
|
}
|
|
106
|
+
await delay(delayMs);
|
|
90
107
|
}
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
throw new Error(`Speculos confirmation not reached after ${maxAttempts} attempts`);
|
|
109
|
+
};
|
|
93
110
|
}
|
|
94
111
|
return checkSpeculosLogs().then(transport => {
|
|
95
112
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speculos.js","sourceRoot":"","sources":["../../src/signers/speculos.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,
|
|
1
|
+
{"version":3,"file":"speculos.js","sourceRoot":"","sources":["../../src/signers/speculos.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/coin-tester",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0-nightly.20251126160702",
|
|
4
4
|
"description": "Deterministic testing of Ledger coin-modules",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"dependencies": {
|
|
7
|
+
"@ledgerhq/speculos-device-controller": "0.1.0",
|
|
7
8
|
"axios": "1.12.2",
|
|
8
9
|
"chalk": "^4.1.2",
|
|
9
10
|
"docker-compose": "^1.1.0",
|
|
10
11
|
"lodash": "^4.17.21",
|
|
11
12
|
"rxjs": "7.8.1",
|
|
12
|
-
"@ledgerhq/
|
|
13
|
+
"@ledgerhq/live-dmk-speculos": "^0.2.0-nightly.20251126160702",
|
|
13
14
|
"@ledgerhq/types-devices": "^6.27.0"
|
|
14
15
|
},
|
|
15
16
|
"devDependencies": {
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
"ts-jest": "^28.0.8",
|
|
20
21
|
"typescript": "^5.1.3",
|
|
21
22
|
"@ledgerhq/types-cryptoassets": "^7.30.0",
|
|
22
|
-
"@ledgerhq/types-live": "^6.
|
|
23
|
+
"@ledgerhq/types-live": "^6.90.0-nightly.20251126160702"
|
|
23
24
|
},
|
|
24
25
|
"typesVersions": {
|
|
25
26
|
"*": {
|
package/src/signers/speculos.ts
CHANGED
|
@@ -4,7 +4,8 @@ import fs from "fs/promises";
|
|
|
4
4
|
import * as compose from "docker-compose";
|
|
5
5
|
import axios, { AxiosError } from "axios";
|
|
6
6
|
import { SignOperationEvent } from "@ledgerhq/types-live";
|
|
7
|
-
import
|
|
7
|
+
import { DeviceManagementKitTransportSpeculos } from "@ledgerhq/live-dmk-speculos";
|
|
8
|
+
import { deviceControllerClientFactory } from "@ledgerhq/speculos-device-controller";
|
|
8
9
|
import { ENV } from "../types";
|
|
9
10
|
|
|
10
11
|
const { SPECULOS_API_PORT } = process.env as ENV;
|
|
@@ -48,7 +49,7 @@ export async function spawnSpeculos(
|
|
|
48
49
|
libraries?: Array<{ name: string; endpoint: `/${string}` }>;
|
|
49
50
|
},
|
|
50
51
|
): Promise<{
|
|
51
|
-
transport:
|
|
52
|
+
transport: DeviceManagementKitTransportSpeculos;
|
|
52
53
|
getOnSpeculosConfirmation: (approvalText?: string) => () => Promise<void>;
|
|
53
54
|
}> {
|
|
54
55
|
ensureEnv();
|
|
@@ -89,12 +90,12 @@ export async function spawnSpeculos(
|
|
|
89
90
|
},
|
|
90
91
|
});
|
|
91
92
|
|
|
92
|
-
async function checkSpeculosLogs(): Promise<
|
|
93
|
+
async function checkSpeculosLogs(): Promise<DeviceManagementKitTransportSpeculos> {
|
|
93
94
|
const { out } = await compose.logs("speculos", { cwd, env: process.env });
|
|
94
95
|
|
|
95
96
|
if (out.includes("Server started")) {
|
|
96
97
|
console.log(chalk.bgYellowBright.black(" - SPECULOS READY ✅ - "));
|
|
97
|
-
return
|
|
98
|
+
return DeviceManagementKitTransportSpeculos.open({
|
|
98
99
|
apiPort: SPECULOS_API_PORT,
|
|
99
100
|
});
|
|
100
101
|
}
|
|
@@ -104,27 +105,43 @@ export async function spawnSpeculos(
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
function getOnSpeculosConfirmation(approvalText = "Accept") {
|
|
107
|
-
async function onSpeculosConfirmation(e?: SignOperationEvent): Promise<void> {
|
|
108
|
-
if (e?.type
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (data.events[0].text !== approvalText) {
|
|
114
|
-
await axios.post(`http://localhost:${SPECULOS_API_PORT}/button/right`, {
|
|
115
|
-
action: "press-and-release",
|
|
116
|
-
});
|
|
108
|
+
return async function onSpeculosConfirmation(e?: SignOperationEvent): Promise<void> {
|
|
109
|
+
if (e?.type !== "device-signature-requested") return;
|
|
110
|
+
|
|
111
|
+
const baseURL = `http://127.0.0.1:${SPECULOS_API_PORT}`;
|
|
112
|
+
const buttonClient = deviceControllerClientFactory(baseURL).buttonFactory();
|
|
117
113
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
const maxAttempts = 80;
|
|
115
|
+
const delayMs = 250;
|
|
116
|
+
|
|
117
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
118
|
+
try {
|
|
119
|
+
const { data } = await axios.get(`${baseURL}/events?currentscreenonly=true`, {
|
|
120
|
+
timeout: 2000,
|
|
122
121
|
});
|
|
122
|
+
|
|
123
|
+
const text = data?.events?.[0]?.text;
|
|
124
|
+
if (text === approvalText) {
|
|
125
|
+
await buttonClient.both();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// not on the approval screen yet—scroll right and retry
|
|
130
|
+
await buttonClient.right();
|
|
131
|
+
} catch (err) {
|
|
132
|
+
// retry on network issues
|
|
133
|
+
if (axios.isAxiosError(err)) {
|
|
134
|
+
// fall through to retry
|
|
135
|
+
} else {
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
123
138
|
}
|
|
139
|
+
|
|
140
|
+
await delay(delayMs);
|
|
124
141
|
}
|
|
125
|
-
}
|
|
126
142
|
|
|
127
|
-
|
|
143
|
+
throw new Error(`Speculos confirmation not reached after ${maxAttempts} attempts`);
|
|
144
|
+
};
|
|
128
145
|
}
|
|
129
146
|
|
|
130
147
|
return checkSpeculosLogs().then(transport => {
|