Skip to main content

Midnight.js v3.2.0 release notes

  • Version: v3.2.0
  • Date: March 5, 2026
  • Node.js requirement: >=22

High-level summary

This release focuses on security hardening for private state management, stronger account-level isolation, and improved operational tooling for Midnight.js and testkit workflows.

It introduces new export/import and password rotation capabilities while tightening defaults and validation for secure production usage.

Audience

This release note is most relevant for developers who:

  • Use level-private-state-provider for wallet or private state persistence.
  • Manage signing keys and encrypted private state lifecycle.
  • Operate CI/CD workflows and dependency automation for Midnight.js projects.
  • Need stable test environment support across preprod and preview.

Summary of updates

  • Removed walletProvider config path in favor of password-provider-based storage access.
  • Made accountId mandatory for account-scoped storage isolation.
  • Added secure export/import and password rotation APIs.
  • Strengthened encryption lifecycle, salt handling, and cache invalidation controls.
  • Added testkit environment support for preview and preprod.
  • Delivered bug fixes for WASM payload handling, Zswap state handling, and network validation.

New features

These additions improve developer ergonomics across provider configuration, storage operations, and testing workflows.

Enhanced URL handling in HTTP client proving provider

The httpClientProvingProvider now properly handles URLs with existing paths and query parameters. Previously, URLs with paths would be incorrectly overwritten.

// Now works correctly with URLs containing paths
const provider = httpClientProvingProvider(
'https://prover.example.com/api/v1/', // Path is preserved
zkConfigProvider
);
// Endpoints: /api/v1/check, /api/v1/prove

Signing key export/import

Export and import signing keys with password protection and conflict resolution.

// Export
const keysExport = await provider.exportSigningKeys({ password: 'export-pw' });

// Import with conflict handling
await provider.importSigningKeys(keysExport, {
password: 'export-pw',
conflictStrategy: 'skip' // 'skip' | 'overwrite' | 'error'
});

Private state export/import

Export and import private states with the same security features.

// Export
provider.setContractAddress(contractAddress);
const statesExport = await provider.exportPrivateStates({ password: 'export-pw' });

// Import
await provider.importPrivateStates(statesExport, {
password: 'export-pw',
conflictStrategy: 'overwrite'
});

Password rotation APIs

These APIs provide explicit credential rotation for both private state and signing keys, enabling safer long-running deployments and operational key hygiene.

// Rotate private state password
provider.setContractAddress(contractAddress);
await provider.changePassword(
() => 'old-password',
() => 'new-password'
);

// Rotate signing keys password
await provider.changeSigningKeysPassword(
() => 'old-password',
() => 'new-password'
);

Account migration support

Use account-scoped migration utilities to move existing unscoped data into isolated account namespaces while preserving rollback options.

import { migrateToAccountScoped } from '@midnight-ntwrk/level-private-state-provider';

const result = await migrateToAccountScoped({ accountId: walletAddress });
// Original data preserved for rollback

Mnemonic-based wallet in testkit

New testkit helpers for mnemonic-based wallet generation.

import { FluentWalletBuilder } from '@midnight-ntwrk/testkit';

const wallet = new FluentWalletBuilder()
.withMnemonic('your mnemonic phrase...')
.build();

// Or use predefined test wallet
const testWallet = new FluentWalletBuilder()
.withTestWallet()
.build();

Browser storage warning

Automatic warning when using LevelDB storage in browser environments, alerting users to data persistence risks.

Testkit test environments

Added support for preprod and preview test environments in testkit-js. Developers can now easily configure tests against different Midnight network environments using the MN_TEST_ENVIRONMENT variable.

import { getTestEnvironment, createLogger } from '@midnight-ntwrk/testkit-js';

const logger = createLogger();
const testEnvironment = getTestEnvironment(logger);
const config = await testEnvironment.start();

// config provides: indexer, indexerWS, node, nodeWS, faucet, proofServer
# Run tests against preprod network
MN_TEST_ENVIRONMENT='preprod' yarn test

# Run tests against preview network
MN_TEST_ENVIRONMENT='preview' yarn test

Breaking changes

The following changes are critical and might break existing integrations.

LevelPrivateStateProvider walletProvider option removed

What changed: The walletProvider configuration option has been removed. Instances must use privateStoragePasswordProvider.

What breaks: Any initialization path that still passes walletProvider.

Required actions:

  • Replace walletProvider with privateStoragePasswordProvider.
  • Validate password-provider behavior in all runtime environments.
import { levelPrivateStateProvider } from '@midnight-ntwrk/level-private-state-provider';

// v3.2.0 - walletProvider no longer supported
const provider = levelPrivateStateProvider({
privateStoragePasswordProvider: () => process.env.STORAGE_PASSWORD!,
accountId: walletAddress
});

LevelPrivateStateProvider accountId now required

What changed: accountId is now a required configuration field for storage provider initialization.

What breaks: Any provider setup that omits accountId.

Required actions:

  • Add accountId to all provider instantiations.
  • Use a stable per-account identifier to preserve correct state partitioning.
const provider = levelPrivateStateProvider({
privateStoragePasswordProvider: () => 'password',
accountId: walletAddress // Required - provides data isolation between accounts
});

Auth token removed from compact fetch

What changed: The authToken parameter has been removed from compact fetch operations.

What breaks: Code that still passes authToken to compact fetch helpers.

Required actions:

  • Remove authToken from compact fetch call sites.
  • Verify compact artifact download flows in CI and local development.

Security enhancements

This release includes multiple hardening updates for private state encryption and operational safety.

Multi-version encryption with increased PBKDF2 iterations

  • V2 encryption now uses 600,000 PBKDF2 iterations (up from 100,000 in V1)
  • Automatic migration from V1 to V2 during password rotation
  • Enhanced password validation with character class and pattern checks

Consistent salt generation

  • New getOrCreateSalt utility prevents race conditions in private state operations
  • Salt consistency guaranteed across sequential operations
  • Prevents cryptographic issues from concurrent access

Encryption caching and invalidation

  • Encryption keys are cached to avoid repeated PBKDF2 derivation
  • New invalidateEncryptionCache() API for cache management
  • Automatic cache invalidation after password rotation

Secure password rotation

  • New changePassword() method for private states
  • New changeSigningKeysPassword() method for signing keys
  • Atomic batch writes ensure all-or-nothing re-encryption
  • Rotation locks for safe concurrent read/write operations
  • Automatic V1 to V2 migration during rotation

Account-scoped isolation

  • Each accountId creates isolated storage namespaces
  • Account ID is SHA-256 hashed (32 characters) before use in storage paths
  • New migrateToAccountScoped() function for transitioning from unscoped storage

Scoped transaction identity validation

  • New ScopedTransactionIdentityMismatchError prevents silent state mismatches
  • Identity tracking with CachedStateIdentity interface
  • Validation ensures batched calls target the same contract and private state

Bug fixes

The following fixes resolve runtime and tooling defects reported across Midnight.js modules.

WASM payload buffer copy

Fixed a critical issue where payload.buffer on a WASM subarray view was returning the entire WASM linear memory heap instead of the referenced bytes. This was sending megabytes of unrelated memory to the proof server, causing parse failures like BadInput("Unsupported ZKIR version") or corrupt field values. The fix replaces payload.buffer with new Uint8Array(payload) which copies only the view's bytes.

Zswap chain state handling

Fixed an issue where the initial Zswap chain state was incorrectly merged instead of being reused, potentially causing state inconsistencies.

Lodash dependency removed

Removed lodash dependency and replaced usage with native object spread, reducing bundle size and eliminating a dependency.

Fail fast on unset network ID

Network ID validation now fails immediately with a clear error message when the network ID is not set, instead of silently proceeding and causing cryptic failures downstream.

TransactionContext excluded from circuit call arguments

Fixed an issue where TransactionContext was incorrectly included in circuit call arguments, which could cause unexpected behavior in contract interactions.

Refactoring

Internal cleanup updates improve type precision and maintainability.

Wallet state provider types

Updated wallet state provider to use ShieldedWalletAPI and UnshieldedWalletAPI types for improved type specificity.

Testing

This release also adds broader automated coverage for storage and environment scenarios.

  • Added comprehensive integration tests for Level Private State Provider export/import functionality
  • Added test environments for preprod and preview networks in testkit

Known issues

No critical known issues were identified at release time.