Skip to content

vetkeys examples: migrate to icp-cli, @icp-sdk/core, and @icp-sdk/vetkeys 0.5.0 #1343

@marc0olo

Description

@marc0olo

Background

The vetkeys examples were previously maintained in dfinity/vetkeys and have since moved to this repo. A migration PR (dfinity/vetkeys#366) was developed there but never merged — it was closed when the examples moved. All the work it describes needs to land here instead.

The changes fall into two buckets:

  • Bucket 1 — Independent of any library release; can be done now.
  • Bucket 2 — Requires `@icp-sdk/vetkeys` 0.5.0 to be published to npm first (tracked in dfinity/vetkeys#384).

Bucket 1 — Can be done now

1. Backend: replace `dfx.json` with `icp.yaml` (all 7 examples)

All 7 example backends currently use `dfx.json`. Replace with `icp.yaml` for all Motoko and Rust backends:

  • `basic_bls_signing`
  • `basic_ibe`
  • `basic_timelock_ibe`
  • `encrypted_chat`
  • `encrypted_notes_dapp_vetkd`
  • `password_manager`
  • `password_manager_with_metadata`

Also:

  • Update all `Makefile`s to call `icp` instead of `dfx`
  • In all `mops.toml` files: pin `moc = "1.5.0"` in a `[toolchain]` section and remove the `--enhanced-orthogonal-persistence` flag from `[moc] args` (it is the default since moc 0.15.0)
  • Update Rust backend for `password_manager_with_metadata` to the current `ic-vetkeys` crate interface (the `KeyManager` API changed in 0.5.0)
  • Use `test_key_1` instead of `dfx_test_key` in `icp.yaml` configs and canister integration tests (standardise on the icp-cli/PocketIC key name; the library retains backward-compatible handling of `dfx_test_key`)

2. Frontend: replace `@dfinity/*` with `@icp-sdk/core` (all 7 examples)

  • Replace `@dfinity/auth-client` with `@icp-sdk/auth`
  • Replace `@dfinity/principal`, `@dfinity/agent`, `@dfinity/candid`, `@dfinity/identity` with `@icp-sdk/core` equivalents
  • Update all `vite.config.ts` files accordingly
  • Update all `gen_bindings.sh` scripts to use `icp-cli` (i.e. call `icp generate` instead of `dfx generate`)
  • Add `dev:motoko` / `dev:rust` npm scripts to distinguish which backend to develop against
  • Remove deprecated `baseUrl` from `tsconfig.json` in all examples
  • Rename `tailwind.config.cjs` → `tailwind.config.mjs` in both `password_manager` examples (required by `"type": "module"`)
  • Update `HttpAgent` construction: replace `HttpAgent.createSync()` (deprecated) and `new HttpAgent(options)` (deprecated) with `await HttpAgent.create({ host, identity, ... })`

Important — `gen_bindings.sh` guard: Each example's `gen_bindings.sh` calls `candid-extractor` via a Makefile redirect (`candid-extractor ... > backend.did`). The `>` redirect truncates the `.did` file before the command runs, so if `candid-extractor` is not installed the static `.did` file is silently wiped — causing `bindgen` to read an empty file and generate a `did.js` with no exports, which breaks the Vite build with `"idlFactory" is not exported`. Fix: wrap the extraction call with `if command -v candid-extractor >/dev/null 2>&1` so that the committed `.did` files are left intact when the tool is absent.

3. Frontend source: critical runtime fixes (all affected examples)

These bugs were discovered during testing against the 0.5.0 API. They will cause runtime failures regardless of library version:

  • `encrypted_chat` — Fix actor caching in the auth store: actors must be created once on login and cached, not re-created on each call.
  • `encrypted_chat` — Fix `DerivedKeyMaterial.fromCryptoKey()` missing `await` (the method is now async).
  • `encrypted_chat` — Add the required `associatedData` argument to `encryptMessage()` / `decryptMessage()`.
  • `encrypted_notes_dapp_vetkd` — Rewrite `crypto.ts`: `deriveAesGcmCryptoKey()` is now `@internal`; encrypt/decrypt must go through `DerivedKeyMaterial.encryptMessage()` / `decryptMessage()` directly. Additionally, `DerivedKeyMaterial` class instances are not structured-clone safe so they cannot be stored directly in IndexedDB — cache the `CryptoKey` in IndexedDB and reconstruct the `DerivedKeyMaterial` on retrieval via `DerivedKeyMaterial.fromCryptoKey()`.
  • All examples — Rename `getBasicIbeCanister` → `getBasicIbeActor` (and equivalent functions in other examples) for naming consistency.
  • All examples — Remove the `window.global` polyfill and `as any` casts that were previously required but are no longer needed.

4. CI: update workflows to use icp-cli

  • Replace `dfx start` / `dfx deploy` with `icp network start` / `icp deploy` in all example CI workflows
  • Remove `DFX_VERSION` env vars; add a Node.js 22 setup step (icp-cli requires Node ≥ 22)
  • Update provision scripts (`provision-darwin.sh`, `provision-linux.sh`) to install `icp-cli` instead of `dfx`; also install `ic-mops` globally (required before `icp deploy` for Motoko canisters)
  • Use `ICP_CLI_GITHUB_TOKEN` (not `GITHUB_TOKEN`) on all steps that call `icp` — icp-cli uses this specific env var when fetching the network launcher to avoid GitHub rate limits
  • Fix flaky `should_access_map_values` integration test: use `BTreeMap` instead of `Vec` for key-value pairs so duplicate key collisions update the expected value correctly rather than causing spurious failures

5. Docs

  • Update all `internetcomputer.org/docs/` links → `docs.internetcomputer.org/`
  • Replace IC SDK install instructions with ICP CLI references
  • Add `icp network stop` instructions to the local deployment sections of all READMEs
  • Comment out icp.ninja launch badges for now — icp.ninja currently requires dfx; re-enable once icp.ninja supports icp-cli
  • Fix broken anchor in `encrypted_chat/SPEC.md`: `#state-cache` → `#encrypted-symmetric-ratchet-state-cache`

Bucket 2 — Blocked on `@icp-sdk/vetkeys` 0.5.0 npm release

Once dfinity/vetkeys#384 is merged and the `npm/0.5.0` tag is pushed:

  • Replace all `@dfinity/vetkeys` references (or local `file:` paths) with `@icp-sdk/vetkeys ^0.5.0` in all 7 example `package.json` files
  • Update all `DefaultEncryptedMapsClient` / `DefaultKeyManagerClient` constructor call sites: the constructors now accept an `HttpAgent` directly instead of `HttpAgentOptions` (the agent must be created by the caller via `await HttpAgent.create(...)` before being passed in)

Known pre-existing issues in `encrypted_chat` (not introduced by this migration)

The `encrypted_chat` example is an unfinished prototype (the README carries a disclaimer). The following gaps between `SPEC.md` and the actual implementation predate this migration and should not be fixed as part of this issue — they are called out here for awareness only:

  1. `get_my_chats_and_time` vs `get_my_chat_ids`: SPEC defines an API returning `{chats, consensus_time_now}` but backend/frontend use `get_my_chat_ids` returning only an array of tuples.
  2. Extra parameter in create-chat APIs: SPEC says `create_direct_chat(OtherParticipant, SymmetricKeyRotationMins)` but both sides pass `messageExpirationDurationMinutes` as a third parameter.
  3. `derive_chat_vetkey` VetKeyEpochId: optional in code (`[] | [bigint]`), required in SPEC.
  4. Nonce type mismatch: SPEC defines `Nonce = blob`, backend DID uses `bigint`.
  5. 8-byte vs 16-byte nonces: SPEC specifies 16 bytes; frontend uses 8-byte nonces.

Test plan (from dfinity/vetkeys#366)

  • `basic_ibe`: `icp network start -d && icp deploy` (Motoko + Rust), verify encrypt/decrypt flow
  • `basic_bls_signing`: verify sign/verify flow
  • `basic_timelock_ibe`: verify timelock decrypt at future epoch
  • `encrypted_notes_dapp_vetkd`: add note, reload page (tests IndexedDB cache path), verify decrypt
  • `encrypted_chat`: send message, verify decryption on both ends
  • `password_manager`: add vault entry, verify encrypt/decrypt
  • `password_manager_with_metadata`: same as above with metadata fields
  • CI passes on all example workflow jobs

Reference

Full context, commit-by-commit breakdown, and the complete diff are in dfinity/vetkeys#366.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions