Skip to content

Migrate example-bboard to Midnight Ledger v8#1350

Open
aagargoura wants to merge 19 commits intomidnightntwrk:mainfrom
aagargoura:migration-example-bboard-ledger-v8
Open

Migrate example-bboard to Midnight Ledger v8#1350
aagargoura wants to merge 19 commits intomidnightntwrk:mainfrom
aagargoura:migration-example-bboard-ledger-v8

Conversation

@aagargoura
Copy link
Copy Markdown
Contributor

@aagargoura aagargoura commented Mar 25, 2026

Summary

Migrate example-bboard to Midnight Ledger v8. Ledger v7 is no longer supported as of this release.

This PR updates all Midnight SDK dependencies, adapts to breaking API changes, recompiles the contract with the new Compact compiler, bumps Vite to the latest major version, and fixes runtime issues discovered during preprod/preview testing.

Dependency Updates

Package Before After
@midnight-ntwrk/ledger v7 (7.0.0) v8 (8.0.3)
@midnight-ntwrk/midnight-js-* 3.0.0 4.0.2
@midnight-ntwrk/testkit-js 3.0.0 4.0.2
@midnight-ntwrk/dapp-connector-api 4.0.0 4.0.1
@midnight-ntwrk/wallet-sdk-facade 1.0.0 3.0.0
@midnight-ntwrk/wallet-sdk-address-format 3.0.0 3.1.0
midnightntwrk/proof-server 8.0.2 8.0.3
Compact Compiler 0.29.0 0.30.0
Vite 7.3.1 8.0.2
tsx 4.21.0 (new)

Breaking Changes Addressed

Ledger v7 to v8

  • All @midnight-ntwrk/ledger-v7 imports updated to @midnight-ntwrk/ledger-v8
  • @midnight-ntwrk/onchain-runtime-v2 references updated to @midnight-ntwrk/onchain-runtime-v3 in Vite config

DustWalletState API

  • dustState.dustAddress replaced with dustState.address
  • dustState.walletBalance() replaced with dustState.balance()
  • UtxoWithMeta is no longer exported from @midnight-ntwrk/wallet-sdk-dust-wallet; unshielded UTXOs are now mapped from the Data.Class format (utxo/meta nested properties) to the flat format expected by the dust wallet

Wallet SDK Type Changes

  • ShieldedWallet and UnshieldedWallet are now type aliases (not classes), so instanceof checks no longer work; function parameter types updated to ShieldedWalletAPI / UnshieldedWalletAPI
  • ShieldedWalletState.address.coinPublicKeyString() replaced with address.coinPublicKey.toHexString()
  • Removed unused getInitialState function that relied on instanceof

LevelDB Private State Provider

  • levelPrivateStateProvider now requires a mandatory accountId field for namespace isolation between accounts
  • Password complexity now requires at least 3 character categories (uppercase, lowercase, digits, special characters)

PrivateStateProvider Interface

  • Added setContractAddress() method required for scoping operations
  • Added exportPrivateStates() / importPrivateStates() stubs (not applicable to in-memory browser provider)
  • Added exportSigningKeys() / importSigningKeys() stubs (not applicable to in-memory browser provider)

Contract Address Scoping for Private State

  • PrivateStateProvider now requires setContractAddress() to be called before accessing state
  • For deploy(): pass fresh private state directly instead of querying the provider (no contract address exists yet)
  • For join(): call setContractAddress(contractAddress) before any private state operations

Contract Recompilation

  • Recompiled with Compact compiler 0.30.0; generated bindings now include provableCircuits required by compact-runtime 0.15.0

Node.js Loader Compatibility

  • Replaced --experimental-specifier-resolution=node --loader ts-node/esm with node --import tsx in CLI launcher scripts (the old flags were removed/deprecated in Node.js v24)
  • Added .js extensions to extensionless relative imports in bboard-cli/src/index.ts

Runtime Fixes

  • Wallet funding flow: Fixed waitForUnshieldedFunds returning immediately with 0 balance after sync; now continues listening for incoming funds with a 600s timeout
  • Contract address scoping: Fixed "Contract address not set" error on deploy by using fresh private state directly, and calling setContractAddress() before join
  • CLI hanging on Node v24: Replaced deprecated --experimental-specifier-resolution=node and --loader ts-node/esm flags with tsx
  • Password complexity: Updated private state provider password to meet new Ledger v8 complexity requirements
  • CLI error handling: Wrapped post() and takeDown() in try/catch so contract errors (e.g., posting to an occupied board) log the error and return to the menu instead of crashing

Improvements

  • Added elapsed time logging for deploy, join, post, and takeDown operations (logs every 5s + total duration)
  • Simplified Vite config for Vite 8 (Rolldown): removed vite-plugin-top-level-await, commonjsOptions, esbuildOptions, and custom wasm-module-resolver plugin — build time reduced from 3s to 0.75s (4x faster), bundle size reduced by 15%
  • Added isomorphic-ws shim to resolve Rolldown IMPORT_IS_UNDEFINED WebSocket warnings in UI build
  • Configured ESLint no-unused-vars to ignore _-prefixed params/vars

Other Changes

  • Updated CI workflow to use Compact compiler 0.30.0
  • Updated Vite from 7.3.1 to 8.0.2
  • Updated README: TypeScript 5.9.3, Node.js v24.14.0, Docker 29.3.0, Lace wallet instructions for both networks, fixed Preview faucet link, simplified install steps
  • Updated proof server Docker images from 8.0.2 to 8.0.3

Test Plan

  • contract: npm run ci passes (compile, typecheck, lint, build, 9/9 tests)
  • api: npm run ci passes (typecheck, lint, build)
  • bboard-cli: npm run ci passes (typecheck, lint, build)
  • bboard-ui: npm run ci passes (typecheck, lint)
  • bboard-ui: npm run ci passes (typecheck, lint, build for preprod and preview)
  • Tested on Preprod network — deploy, post, take down, join all working
  • Tested on Preview network — deploy, post, take down, join all working

References

- @midnight-ntwrk/ledger-v7 7.0.0 → @midnight-ntwrk/ledger-v8 8.0.3
- @midnight-ntwrk/midnight-js-* 3.0.0 → 4.0.2
- @midnight-ntwrk/testkit-js 3.0.0 → 4.0.2
- @midnight-ntwrk/dapp-connector-api 4.0.0 → 4.0.1
- @midnight-ntwrk/wallet-sdk-facade 1.0.0 → 3.0.0
- @midnight-ntwrk/wallet-sdk-address-format 3.0.0 → 3.1.0
…2 to v3

Update all import paths from @midnight-ntwrk/ledger-v7 to
@midnight-ntwrk/ledger-v8 and @midnight-ntwrk/onchain-runtime-v2 to
@midnight-ntwrk/onchain-runtime-v3 across CLI, UI, and shared modules.
- dustAddress → address
- walletBalance() → balance()
- Remove UtxoWithMeta import from wallet-sdk-dust-wallet (no longer exported)
- Map unshielded UtxoWithMeta (now Data.Class with utxo/meta) to flat format
- ShieldedWallet/UnshieldedWallet are now type aliases, not classes;
  use ShieldedWalletAPI/UnshieldedWalletAPI for function parameters
- Remove unused getInitialState (relied on instanceof which no longer works)
- ShieldedWalletState.address.coinPublicKeyString() → address.coinPublicKey.toHexString()
The Ledger v8 SDK now requires an accountId field for namespace
isolation between different accounts/wallets using the same database.
Add setContractAddress and export/import stub methods required by the
updated PrivateStateProvider interface in midnight-js-types 4.0.2.
Export/import operations throw as they are not applicable to the
in-memory browser provider.
@aagargoura aagargoura requested review from a team as code owners March 25, 2026 17:13
@aagargoura aagargoura closed this Mar 25, 2026
@aagargoura aagargoura reopened this Mar 25, 2026
@aagargoura aagargoura marked this pull request as draft March 25, 2026 17:41
The Ledger v8 PrivateStateProvider requires setContractAddress() before
any get/set operations. For deploy, use fresh state directly since no
contract address exists yet. For join, set the known address first.
Previously waitForUnshieldedFunds returned immediately after sync even
with 0 balance, causing the CLI to exit. Now it continues listening for
state changes until a non-zero balance appears (10 min timeout).
--experimental-specifier-resolution=node was removed in Node v24 and
--loader is deprecated. Switch to tsx via --import for TypeScript
execution. Also fix extensionless relative imports in the CLI.
…ssword complexity

- Wrap post() and takeDown() calls in try/catch so errors are logged
  instead of crashing the CLI menu loop
- Update private state provider password to meet new Ledger v8 complexity
  requirements (min 3 character categories)
Log elapsed time every 5 seconds and total duration for deploy, join,
post, and takeDown operations to give users visibility while waiting.
Remove deprecated/unnecessary plugins and options:
- Remove vite-plugin-top-level-await (native in Vite 8)
- Remove commonjsOptions (deprecated, Rolldown handles CJS natively)
- Remove esbuildOptions (deprecated, replaced by Rolldown)
- Remove custom wasm-module-resolver plugin (no longer needed)
- Convert manualChunks from object to function (Vite 8 requirement)

Build time improved from 3s to 0.75s, bundle size reduced by 15%.
Add a shim that re-exports globalThis.WebSocket as both default and
named export, fixing Rolldown IMPORT_IS_UNDEFINED warnings from the
Midnight SDK's usage of isomorphic-ws.
- Update TypeScript badge to 5.9.3, Node.js to v24.14.0, Docker to 29.3.0
- Update Lace wallet instructions to support both Preprod and Preview
- Fix Preview faucet link (was pointing to preprod)
- Remove redundant npm install from sub-package build steps (workspaces)
- Simplify install instructions to single root npm install
- Rename isomorphic-ws-shim.js to .ts so ESLint projectService can parse it
- Configure no-unused-vars to ignore _-prefixed params/vars
- Prefix unused currentContractAddress with underscore
@aagargoura aagargoura marked this pull request as ready for review March 25, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant