Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/_ledgernano.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ jobs:

- name: Download ledgernano binary
run: |
curl -L -o nanos.tar.gz https://github.com/iotaledger/ledger-app-iota/releases/download/ledger-app-iota-v0.9.2/nanos.tar.gz
tar -xvf nanos.tar.gz
mv nanos/iota sdk/ledgerjs-hw-app-iota/tests/iota
curl -L -o nanox.tar.gz https://github.com/iotaledger/ledger-app-iota/releases/download/ledger-app-iota-v1.0.0/nanox.tar.gz
tar -xvf nanox.tar.gz
mv nanox/iota sdk/ledgerjs-hw-app-iota/tests/iota

- name: Start speculos simulator
run: docker run --rm -d -p 5000:5000 -v $(pwd)/sdk/ledgerjs-hw-app-iota/tests:/app ghcr.io/ledgerhq/speculos --api-port 5000 --display headless /app/iota
run: |
# Start the container in detached mode and capture its ID
container_id=$(docker run --rm -d -p 5000:5000 -v $(pwd)/sdk/ledgerjs-hw-app-iota/tests:/app ghcr.io/ledgerhq/speculos --api-port 5000 --display headless /app/iota)

# Print logs for 5 seconds
timeout 5 docker logs -f $container_id || true

- name: Run TS SDK ledgernano tests
run: pnpm --filter @iota/ledgerjs-hw-app-iota test
2 changes: 1 addition & 1 deletion apps/wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"@keystonehq/animated-qr": "^0.10.0",
"@keystonehq/keystone-sdk": "^0.11.4",
"@ledgerhq/errors": "^6.12.4",
"@ledgerhq/hw-transport": "^6.31.0",
"@ledgerhq/hw-transport": "^6.31.12",
"@ledgerhq/hw-transport-webhid": "^6.27.15",
"@ledgerhq/hw-transport-webusb": "^6.27.13",
"@ledgerhq/logs": "^6.12.0",
Expand Down
86 changes: 53 additions & 33 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions sdk/ledgerjs-hw-app-iota/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@
"test:watch": "vitest"
},
"dependencies": {
"@ledgerhq/hw-transport": "^6.31.0",
"@ledgerhq/hw-transport": "^6.31.12",
"fast-sha256": "^1.3.0"
},
"devDependencies": {
"@iota/build-scripts": "workspace:*",
"@ledgerhq/hw-transport-mocker": "^6.29.0",
"@ledgerhq/hw-transport-node-speculos-http": "^6.29.2",
"@ledgerhq/hw-transport-mocker": "^6.29.12",
"@ledgerhq/hw-transport-node-speculos-http": "^6.30.2",
"@size-limit/preset-small-lib": "^11.1.4",
"@types/node": "^20.14.10",
"axios": "^1.12.0",
Expand Down
70 changes: 45 additions & 25 deletions sdk/ledgerjs-hw-app-iota/tests/Iota.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,28 @@ import Iota from '../src/Iota';

const API_PORT: number = 5000;
const SPECULOS_BASE_URL: string = `http://127.0.0.1:${API_PORT}`;

// Before running the tests you need to install speculos and start the iota app with it.
// If the binary is not available, download it:
// gh release download --repo https://github.com/iotaledger/ledger-app-iota -p nanos.tar.gz ledger-app-iota-v0.9.2
// tar -xvf nanos.tar.gz
// sudo apt-get install qemu-user-static libxcb-xinerama0 // might be needed for speculos to work
// pip install speculos
// Finally to start the emulator:
// speculos --api-port 5000 --display headless ./sdk/ledgerjs-hw-app-iota/tests/iota
const SPECULOS_HTTP_TRANSPORT_OPTS = {
apiPort: API_PORT.toString(),
};
const TEST_TIMEOUT_MS = 40000;
const WAIT_TIME_MS = 7000;
const PRESS_TIME_MS = 500;
// Before running the tests, pull the speculos Docker image and download the ledgernano binary.
// Then start the speculos simulator and run the tests.
//
// Pull speculos docker image:
// docker pull ghcr.io/ledgerhq/speculos
//
// Download ledgernano binary:
// curl -L -o nanox.tar.gz https://github.com/iotaledger/ledger-app-iota/releases/download/ledger-app-iota-v1.0.0/nanox.tar.gz
// tar -xvf nanox.tar.gz
// mv nanox/iota sdk/ledgerjs-hw-app-iota/tests/iota
//
// Start speculos simulator:
// docker run --rm -d -p 5000:5000 -v $(pwd)/sdk/ledgerjs-hw-app-iota/tests:/app ghcr.io/ledgerhq/speculos --api-port 5000 --display headless /app/iota
//
// Run tests:
// pnpm --filter @iota/ledgerjs-hw-app-iota test
describe.sequential('Test ledgerjs-hw-app-iota', () => {
it('Iota init', async () => {
const transport = await openTransportReplayer(RecordStore.fromString(''));
Expand All @@ -27,7 +40,7 @@ describe.sequential('Test ledgerjs-hw-app-iota', () => {
});

it('Test address generation', async () => {
const transport = await SpeculosHttpTransport.open({});
const transport = await SpeculosHttpTransport.open(SPECULOS_HTTP_TRANSPORT_OPTS);
const ledgerClient = new Iota(transport);

const { publicKey } = await ledgerClient.getPublicKey(`m/44'/4218'/0'/0'/0'`);
Expand All @@ -36,10 +49,11 @@ describe.sequential('Test ledgerjs-hw-app-iota', () => {
expect(Buffer.from(publicKey).toString('hex')).toBe(
'f0a9c612b7e69f1a114aa9189c1f32997d395d09d183368ddfd6d5dc49e34647',
);
await Axios.delete(SPECULOS_BASE_URL + '/events');
});

it('Test address generation with display', async () => {
const transport = await SpeculosHttpTransport.open({});
it('Test address generation with display', { timeout: TEST_TIMEOUT_MS }, async () => {
const transport = await SpeculosHttpTransport.open(SPECULOS_HTTP_TRANSPORT_OPTS);
const ledgerClient = new Iota(transport);

let addressReceived = false;
Expand All @@ -55,19 +69,21 @@ describe.sequential('Test ledgerjs-hw-app-iota', () => {
.catch((err) => {
throw new Error(err);
});
await new Promise((resolve) => setTimeout(resolve, 1000));
// Send requests to approve the shown address
for (let i = 0; i < 6; i++) {
for (let i = 0; i < 3; i++) {
await Axios.post(SPECULOS_BASE_URL + '/button/right', { action: 'press-and-release' });
await new Promise((r) => setInterval(r, PRESS_TIME_MS));
}
await Axios.post(SPECULOS_BASE_URL + '/button/both', { action: 'press-and-release' });
await new Promise((r) => setInterval(r, WAIT_TIME_MS));
if (!addressReceived) {
throw new Error(`Didn't receive address in time`);
}
await Axios.delete(SPECULOS_BASE_URL + '/events');
});

it('Test signing', { timeout: 10000 }, async () => {
const transport = await SpeculosHttpTransport.open({});
it('Test signing', { timeout: TEST_TIMEOUT_MS }, async () => {
const transport = await SpeculosHttpTransport.open(SPECULOS_HTTP_TRANSPORT_OPTS);
const ledgerClient = new Iota(transport);
let signatureReceived = false;
ledgerClient
Expand All @@ -89,28 +105,29 @@ describe.sequential('Test ledgerjs-hw-app-iota', () => {
.catch((err) => {
throw new Error(err);
});
await new Promise((resolve) => setTimeout(resolve, 500));
await new Promise((resolve) => setTimeout(resolve, WAIT_TIME_MS));
// Send requests to approve the tx
for (let i = 0; i < 14; i++) {
for (let i = 0; i < 7; i++) {
await Axios.post(SPECULOS_BASE_URL + '/button/right', { action: 'press-and-release' });
await new Promise((r) => setInterval(r, PRESS_TIME_MS));
}
await Axios.post(SPECULOS_BASE_URL + '/button/both', { action: 'press-and-release' });
await new Promise((resolve) => setTimeout(resolve, 2000));
await new Promise((resolve) => setTimeout(resolve, WAIT_TIME_MS));
if (!signatureReceived) {
throw new Error(`Didn't receive signature in time`);
}
await Axios.delete(SPECULOS_BASE_URL + '/events');
});

it('Test blind signing', { timeout: 10000 }, async () => {
it('Test blind signing', { timeout: TEST_TIMEOUT_MS }, async () => {
// Enable blind signing
await Axios.post(SPECULOS_BASE_URL + '/button/right', { action: 'press-and-release' });
await Axios.post(SPECULOS_BASE_URL + '/button/right', { action: 'press-and-release' });
await Axios.post(SPECULOS_BASE_URL + '/button/both', { action: 'press-and-release' });
await Axios.post(SPECULOS_BASE_URL + '/button/both', { action: 'press-and-release' });
await Axios.post(SPECULOS_BASE_URL + '/button/right', { action: 'press-and-release' });
await Axios.post(SPECULOS_BASE_URL + '/button/both', { action: 'press-and-release' });

const transport = await SpeculosHttpTransport.open({});
const transport = await SpeculosHttpTransport.open(SPECULOS_HTTP_TRANSPORT_OPTS);
const ledgerClient = new Iota(transport);
let signatureReceived = false;
ledgerClient
Expand All @@ -132,15 +149,18 @@ describe.sequential('Test ledgerjs-hw-app-iota', () => {
.catch((err) => {
throw new Error(err);
});
await new Promise((resolve) => setTimeout(resolve, 500));
await new Promise((resolve) => setTimeout(resolve, WAIT_TIME_MS));
// Send requests to approve the tx
for (let i = 0; i < 8; i++) {
await Axios.post(SPECULOS_BASE_URL + '/button/both', { action: 'press-and-release' });
for (let i = 0; i < 3; i++) {
await Axios.post(SPECULOS_BASE_URL + '/button/right', { action: 'press-and-release' });
await new Promise((r) => setInterval(r, PRESS_TIME_MS));
}
await Axios.post(SPECULOS_BASE_URL + '/button/both', { action: 'press-and-release' });
await new Promise((resolve) => setTimeout(resolve, 2000));
await new Promise((resolve) => setTimeout(resolve, WAIT_TIME_MS));
if (!signatureReceived) {
throw new Error(`Didn't receive signature in time`);
}
await Axios.delete(SPECULOS_BASE_URL + '/events');
});
});
Loading