mcpField
M
midnight-js

midnight-js

github.com/kali-decoder開発18131 回インストール1 日前に更新
リポジトリ

midnight-js について

Midnight.js TypeScript SDK を使って Midnight Network 上に DApp を構築するためのリファレンススキルです。ブラウザーと Node.js のワークフローに向け、ウォレットと Provider の設定、コントラクト操作、ネットワーク設定、統合テストを扱います。

主な機能

  1. 01Midnight.js のパッケージと Provider のガイド
  2. 02ネットワークとエンドポイントの設定
  3. 03ブラウザーとヘッドレスウォレットの設定
  4. 04コントラクトのデプロイ、呼び出し、確認
  5. 05プライベート状態 Provider の選択肢
  6. 06Testkit による統合テスト

活用シーン

  1. 01Midnight.js DApp プロジェクトのセットアップ
  2. 02ブラウザーまたは Node.js ウォレットの設定
  3. 03コントラクトのデプロイと操作
  4. 04Midnight の統合テストの実行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kali-decoder/midnight-skills --skill midnight-js

インストール後、Claude Code で/midnight-jsを入力して読み込まれたか確認します。

詳細

Midnight.js スキル

Midnight.js は、Midnight Network 上で DApp を構築するための TypeScript SDK で、Ethereum の Web3.js に相当します。公式 SDK ページは「近日公開予定」です。このスキルは、公式の Counter CLI チュートリアルと 1AM スターターテンプレートに基づいています。

主なリファレンス:

  • docs.midnight.network/tutorials/counter/counter-cli — 公式の完全な実装
  • github.com/midnightntwrk/example-counter — リファレンスリポジトリ(Node.js/ヘッドレスウォレット)
  • github.com/webisoftSoftware/1AM-starter-template — ブラウザーウォレット版

1) パッケージ一覧

パッケージ用途
@midnight-ntwrk/midnight-js-contractsdeployContract、findDeployedContract、submitCallTx
@midnight-ntwrk/midnight-js-typesMidnightProviders、WalletProvider、MidnightProvider、createProofProvider
@midnight-ntwrk/midnight-js-indexer-public-data-providerindexerPublicDataProvider(GraphQL インデクサークライアント)
@midnight-ntwrk/midnight-js-fetch-zk-config-providerFetchZkConfigProvider(ブラウザー/CDN)
@midnight-ntwrk/midnight-js-node-zk-config-providerNodeZkConfigProvider(Node.js/ファイルシステム)
@midnight-ntwrk/midnight-js-http-client-proof-providerhttpClientProofProvider(セルフホスト可能な証明サーバー)
@midnight-ntwrk/midnight-js-level-private-state-providerlevelPrivateStateProvider(永続的な LevelDB プライベート状態)
@midnight-ntwrk/midnight-js-network-idsetNetworkId、getNetworkId
@midnight-ntwrk/compact-runtimeContractState(インデクサーのデシリアライズ)
@midnight-ntwrk/ledger-v8Transaction、LedgerParameters、ZswapSecretKeys、DustSecretKey
@midnight-ntwrk/compact-jsCompiledContract、ImpureCircuitId
@midnight-ntwrk/wallet-sdk-facadeWalletFacade(統合ウォレット)
@midnight-ntwrk/wallet-sdk-hdHDWallet、generateRandomSeed、Roles
@midnight-ntwrk/wallet-sdk-shieldedShieldedWallet
@midnight-ntwrk/wallet-sdk-unshielded-walletUnshieldedWallet、createKeystore、PublicKey
@midnight-ntwrk/wallet-sdk-dust-walletDustWallet
@midnight-ntwrk/wallet-sdk-address-formatMidnightBech32m、ShieldedAddress など

2) ネットワーク設定

SDK の操作を行う前に、必ず setNetworkId を呼び出してください。 すべてのライブラリが自動的に使用するグローバル値を設定します。

import { setNetworkId, getNetworkId } from '@midnight-ntwrk/midnight-js-network-id';

// Call once at startup, in the config constructor or before building providers
setNetworkId('preprod'); // 'preprod' | 'preview' | 'mainnet' | 'undeployed'

ネットワークエンドポイント:

ネットワークインデクサー HTTPインデクサー WSRPC
preprodhttps://indexer.preprod.midnight.network/api/v4/graphqlwss://indexer.preprod.midnight.network/api/v4/graphql/wshttps://rpc.preprod.midnight.network
previewhttps://indexer.preview.midnight.network/api/v4/graphqlwss://indexer.preview.midnight.network/api/v4/graphql/wswss://rpc.preview.midnight.network
mainnethttps://indexer.mainnet.midnight.network/api/v4/graphqlwss://indexer.mainnet.midnight.network/api/v4/graphql/wshttps://rpc.mainnet.midnight.network
undeployed(ローカル)http://localhost:8088/api/v4/graphqlws://localhost:8088/api/v4/graphql/wsws://localhost:9944

3) コンパイル済みコントラクトの設定

コントラクトはデプロイや呼び出しのたびにではなく、モジュールの読み込み時に一度だけ事前コンパイルしてください。

import { CompiledContract } from '@midnight-ntwrk/compact-js';
import { Contract, witnesses } from './managed/counter'; // generated by compact compiler

// Node.js: load ZK assets from filesystem
import { NodeZkConfigProvider } from '@midnight-ntwrk/midnight-js-node-zk-config-provider';
const zkConfigPath = path.resolve('contract/src/managed/counter');

const compiledContract = CompiledContract.make('counter', Contract).pipe(
  CompiledContract.withVacantWitnesses,
  CompiledContract.withCompiledFileAssets(zkConfigPath),
);

// Browser / CDN: load ZK assets via fetch
import { FetchZkConfigProvider } from '@midnight-ntwrk/midnight-js-fetch-zk-config-provider';
const compiledContract = CompiledContract.make('YourContract', Contract).pipe(
  CompiledContract.withVacantWitnesses,
  CompiledContract.withCompiledFileAssets('/zk/your-contract'),
);

4) 型定義(重要なパターン)

Midnight.js のパターンに従い、コントラクトのプロバイダーに型付きエイリアスを定義します。

import type { MidnightProviders } from '@midnight-ntwrk/midnight-js-types';
import type { DeployedContract, FoundContract } from '@midnight-ntwrk/midnight-js-contracts';
import type { ImpureCircuitId } from '@midnight-ntwrk/compact-js';
import { Counter, type CounterPrivateState } from './managed/counter';

// Extract circuit IDs from the contract type
export type CounterCircuits = ImpureCircuitId<Counter.Contract<CounterPrivateState>>;

// Private state key (string literal type)
export const CounterPrivateStateId = 'counterPrivateState' as const;
export type CounterPrivateStateId = typeof CounterPrivateStateId;

// Full providers type for this contract
export type CounterProviders = MidnightProviders<
  CounterCircuits,
  CounterPrivateStateId,
  CounterPrivateState
>;

// Contract instance types
export type CounterContract = Counter.Contract<CounterPrivateState>;
export type DeployedCounterContract = DeployedContract<CounterContract> | FoundContract<CounterContract>;

5) ウォレットの設定(Node.js/ヘッドレス)

HD キーの導出
import { HDWallet, generateRandomSeed, Roles } from '@midnight-ntwrk/wallet-sdk-hd';
import * as ledger from '@midnight-ntwrk/ledger-v8';
import { Buffer } from 'buffer';

// Generate a fresh random seed (returns Uint8Array)
const seed = generateRandomSeed();
const seedHex = Buffer.from(seed).toString('hex'); // save this

// Or restore from existing hex seed
const seedHex = '...'; // from user input

const hdWallet = HDWallet.fromSeed(Buffer.from(seedHex, 'hex'));
if (hdWallet.type !== 'seedOk') throw new Error('Invalid seed');

const derivationResult = hdWallet.hdWallet
  .selectAccount(0)
  .selectRoles([Roles.Zswap, Roles.NightExternal, Roles.Dust])
  .deriveKeysAt(0);

if (derivationResult.type !== 'keysDerived') throw new Error('Key derivation failed');

hdWallet.hdWallet.clear(); // wipe secret material from memory

const keys = derivationResult.keys;
const shieldedSecretKeys = ledger.ZswapSecretKeys.fromSeed(keys[Roles.Zswap]);
const dustSecretKey = ledger.DustSecretKey.fromSeed(keys[Roles.Dust]);
ウォレットの構築
import { ShieldedWallet } from '@midnight-ntwrk/wallet-sdk-shielded';
import { UnshieldedWallet, createKeystore, PublicKey, InMemoryTransactionHistoryStorage } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
import { DustWallet } from '@midnight-ntwrk/wallet-sdk-dust-wallet';
import { WalletFacade } from '@midnight-ntwrk/wallet-sdk-facade';

const unshieldedKeystore = createKeystore(keys[Roles.NightExternal], getNetworkId());

const shieldedWallet = ShieldedWallet({
  networkId: getNetworkId(),
  indexerClientConnection: { indexerHttpUrl: indexer, indexerWsUrl: indexerWS },
  provingServerUrl: new URL(proofServer),
  relayURL: new URL(node.replace(/^http/, 'ws')), // convert http → ws
}).startWithSecretKeys(shieldedSecretKeys);

const unshieldedWallet = UnshieldedWallet({
  networkId: getNetworkId(),
  indexerClientConnection: { indexerHttpUrl: indexer, indexerWsUrl: indexerWS },
  txHistoryStorage: new InMemoryTransactionHistoryStorage(),
}).startWithPublicKey(PublicKey.fromKeyStore(unshieldedKeystore));

const dustWallet = DustWallet({
  networkId: getNetworkId(),
  costParameters: {
    additionalFeeOverhead: 300_000_000_000_000n,
    feeBlocksMargin: 5,
  },
  indexerClientConnection: { indexerHttpUrl: indexer, indexerWsUrl: indexerWS },
  provingServerUrl: new URL(proofServer),
  relayURL: new URL(node.replace(/^http/, 'ws')),
}).startWithSecretKey(dustSecretKey, ledger.LedgerParameters.initialParameters().dust);

const wallet = new WalletFacade(shieldedWallet, unshieldedWallet, dustWallet);
await wallet.start(shieldedSecretKeys, dustSecretKey);
ウォレットの同期(RxJS パターン — WalletFacade で常に使用)
import * as Rx from 'rxjs';

// Wait until wallet is fully synced
const syncedState = await Rx.firstValueFrom(
  wallet.state().pipe(
    Rx.throttleTime(5_000),
    Rx.filter((state) => state.isSynced),
  ),
);

// Wait until wallet has non-zero unshielded balance
import { unshieldedToken } from '@midnight-ntwrk/ledger-v8';

const balance = await Rx.firstValueFrom(
  wallet.state().pipe(
    Rx.throttleTime(10_000),
    Rx.filter((s) => s.isSynced),
    Rx.map((s) => s.unshielded.balances[unshieldedToken().raw] ?? 0n),
    Rx.filter((balance) => balance > 0n),
  ),
);

Node.js の WebSocket 要件:

import { WebSocket } from 'ws';
// Required for GraphQL subscriptions (wallet sync) to work in Node.js
globalThis.WebSocket = WebSocket as unknown as typeof globalThis.WebSocket;
// Put this at the very top of your entry file, before any wallet imports

6) DUST の生成(Preprod/未デプロイのみ)

NIGHT トークンは時間の経過とともに DUST を生成しますが、UTXO をオンチェーンに明示的に登録した後に限られます。DUST はすべてのトランザクションで使用する、譲渡不可の手数料リソースです。

// 1. Wait for sync
const state = await Rx.firstValueFrom(wallet.state().pipe(Rx.filter((s) => s.isSynced)));

// 2. Check if DUST already available
if (state.dust.availableCoins.length > 0) {
  console.log('DUST already available:', state.dust.walletBalance(new Date()));
  return;
}

// 3. Register unregistered NIGHT UTXOs
const nightUtxos = state.unshielded.availableCoins.filter(
  (coin: any) => coin.meta?.registeredForDustGeneration !== true,
);

if (nightUtxos.length > 0) {
  const recipe = await wallet.registerNightUtxosForDustGeneration(
    nightUtxos,
    unshieldedKeystore.getPublicKey(),
    (payload) => unshieldedKeystore.signData(payload),
  );
  const finalized = await wallet.finalizeRecipe(recipe);
  await wallet.submitTransaction(finalized);
}

// 4. Wait for DUST balance > 0 (may take a few minutes)
await Rx.firstValueFrom(
  wallet.state().pipe(
    Rx.throttleTime(5_000),
    Rx.filter((s) => s.isSynced),
    Rx.filter((s) => s.dust.walletBalance(new Date()) > 0n),
  ),
);

DUST のトラブルシューティング:

  • デプロイ失敗後に DUST 残高が 0 になる → DApp を再起動して、ロックされた DUST コインを解放します
  • pendingCoins > 0 && availableCoins === 0 → DUST が保留中または失敗したトランザクションによってロックされています
  • NIGHT は登録済みなのに DUST = 0 → まだ蓄積中です。数分待ってください

7) プロバイダーの設定

Node.js(セルフホストの証明サーバー)
import { indexerPublicDataProvider } from '@midnight-ntwrk/midnight-js-indexer-public-data-provider';
import { httpClientProofProvider } from '@midnight-ntwrk/midnight-js-http-client-proof-provider';
import { NodeZkConfigProvider } from '@midnight-ntwrk/midnight-js-node-zk-config-provider';
import { levelPrivateStateProvider } from '@midnight-ntwrk/midnight-js-level-private-state-provider';

const zkConfigProvider = new NodeZkConfigProvider<CounterCircuits>(zkConfigPath);

const providers: CounterProviders = {
  privateStateProvider: levelPrivateStateProvider<CounterPrivateStateId>({
    privateStateStoreName: 'counter-private-state',  // LevelDB store name
    walletProvider: walletAndMidnightProvider,
  }),
  publicDataProvider: indexerPublicDataProvider(indexerHttp, indexerWs),
  zkConfigProvider,
  proofProvider: httpClientProofProvider(proofServerUrl, zkConfigProvider),
  walletProvider: walletAndMidnightProvider,
  midnightProvider: walletAndMidnightProvider,
};
ブラウザー(1AM ウォレット/CDN ZK アセット)
import { FetchZkConfigProvider } from '@midnight-ntwrk/midnight-js-fetch-zk-config-provider';
import { indexerPublicDataProvider } from '@midnight-ntwrk/midnight-js-indexer-public-data-provider';
import { createProofProvider } from '@midnight-ntwrk/midnight-js-types';

const config = await connectedAPI.getConfiguration();
setNetworkId(config.networkId);

const zkConfigProvider = new FetchZkConfigProvider(
  new URL(zkAssetBasePath, window.location.origin).toString(),
  window.fetch.bind(window),
);

const provingProvider = await connectedAPI.getProvingProvider(zkConfigProvider);

const providers = {
  publicDataProvider: indexerPublicDataProvider(config.indexerUri, config.indexerWsUri),
  zkConfigProvider,
  proofProvider: createProofProvider(provingProvider),  // wraps 1AM proving provider
  walletProvider: { /* see 1AM skill */ },
  midnightProvider: { /* see 1AM skill */ },
  privateStateProvider: createPrivateStateProvider(), // in-memory for browser
};

8) WalletProvider と MidnightProvider(Node.js ヘッドレス)

これは WalletFacade と midnight-js コントラクト API の間のブリッジです。

import type { WalletProvider, MidnightProvider } from '@midnight-ntwrk/midnight-js-types';
import * as ledger from '@midnight-ntwrk/ledger-v8';

const state = await Rx.firstValueFrom(wallet.state().pipe(Rx.filter((s) => s.isSynced)));

const walletAndMidnightProvider: WalletProvider & MidnightProvider = {
  getCoinPublicKey() {
    return state.shielded.coinPublicKey.toHexString();
  },
  getEncryptionPublicKey() {
    return state.shielded.encryptionPublicKey.toHexString();
  },
  async balanceTx(tx, ttl?) {
    const recipe = await wallet.balanceUnboundTransaction(
      tx,
      { shieldedSecretKeys, dustSecretKey },
      { ttl: ttl ?? new Date(Date.now() + 30 * 60 * 1000) },
    );

    // ⚠️ KNOWN BUG WORKAROUND: wallet SDK signRecipe hardcodes 'pre-proof' but
    // proven (UnboundTransaction) intents contain 'proof' data → "Failed to clone intent"
    // Sign intents manually with the correct proof marker (see signTransactionIntents below)
    signTransactionIntents(recipe.baseTransaction, signFn, 'proof');
    if (recipe.balancingTransaction) {
      signTransactionIntents(recipe.balancingTransaction, signFn, 'pre-proof');
    }

    return wallet.finalizeRecipe(recipe);
  },
  submitTx(tx) {
    return wallet.submitTransaction(tx) as any;
  },
};
「Failed to clone intent」バグの修正
/**
 * Workaround for wallet SDK bug where signRecipe hardcodes 'pre-proof',
 * causing failures when signing proven (UnboundTransaction) intents.
 * Call with proofMarker='proof' for baseTransaction, 'pre-proof' for balancingTransaction.
 */
const signTransactionIntents = (
  tx: { intents?: Map<number, any> },
  signFn: (payload: Uint8Array) => ledger.Signature,
  proofMarker: 'proof' | 'pre-proof',
): void => {
  if (!tx.intents || tx.intents.size === 0) return;

  for (const segment of tx.intents.keys()) {
    const intent = tx.intents.get(segment);
    if (!intent) continue;

    const cloned = ledger.Intent.deserialize<
      ledger.SignatureEnabled, ledger.Proofish, ledger.PreBinding
    >('signature', proofMarker, 'pre-binding', intent.serialize());

    const signature = signFn(cloned.signatureData(segment));

    if (cloned.fallibleUnshieldedOffer) {
      const sigs = cloned.fallibleUnshieldedOffer.inputs.map(
        (_: ledger.UtxoSpend, i: number) =>
          cloned.fallibleUnshieldedOffer!.signatures.at(i) ?? signature,
      );
      cloned.fallibleUnshieldedOffer = cloned.fallibleUnshieldedOffer.addSignatures(sigs);
    }

    if (cloned.guaranteedUnshieldedOffer) {
      const sigs = cloned.guaranteedUnshieldedOffer.inputs.map(
        (_: ledger.UtxoSpend, i: number) =>
          cloned.guaranteedUnshieldedOffer!.signatures.at(i) ?? signature,
      );
      cloned.guaranteedUnshieldedOffer = cloned.guaranteedUnshieldedOffer.addSignatures(sigs);
    }

    tx.intents.set(segment, cloned);
  }
};

9) コントラクトのデプロイと呼び出し

デプロイ
import { deployContract } from '@midnight-ntwrk/midnight-js-contracts';

const deployed = await deployContract(providers, {
  compiledContract,
  privateStateId: CounterPrivateStateId,
  initialPrivateState: { privateCounter: 0 },
});

console.log('Contract address:', deployed.deployTxData.public.contractAddress);
Circuit の呼び出し
// Using callTx (recommended — automatically builds, proves, balances, submits)
const result = await deployed.callTx.increment();
console.log('txId:', result.public.txId);
console.log('blockHeight:', result.public.blockHeight);
既存のコントラクトへの参加
import { findDeployedContract } from '@midnight-ntwrk/midnight-js-contracts';

const contract = await findDeployedContract(providers, {
  contractAddress: '09dbe05f...', // hex string
  compiledContract,
  privateStateId: CounterPrivateStateId,
  initialPrivateState: { privateCounter: 0 },
});

// Now call circuits on it
await contract.callTx.increment();
レジャーの状態を読み取る
import { ContractState } from '@midnight-ntwrk/compact-runtime';
import { Counter } from './managed/counter';

const contractState = await providers.publicDataProvider.queryContractState(contractAddress);

if (contractState === null) {
  console.log('Contract not found');
} else {
  // Apply generated ledger() function to deserialize typed state
  const ledgerState = Counter.ledger(contractState.data);
  console.log('Counter value:', ledgerState.round);
}

10) プライベート状態プロバイダー(インメモリ — ブラウザー/最小構成)

import type {
  PrivateStateProvider, PrivateStateId, PrivateStateExport,
  SigningKeyExport,
} from '@midnight-ntwrk/midnight-js-types';

function createPrivateStateProvider() {
  let scope = '';
  const stateStore = new Map<string, unknown>();
  const signingKeyStore = new Map<string, unknown>();
  const key = (id: string) => `${scope}:${id}`;

  return {
    setContractAddress(address: string) { scope = address; },
    async set(id: string, state: unknown) { stateStore.set(key(id), state); },
    async get(id: string) { return stateStore.get(key(id)) ?? null; },
    async remove(id: string) { stateStore.delete(key(id)); },
    async clear() { stateStore.clear(); },
    async setSigningKey(addr: string, k: unknown) { signingKeyStore.set(addr, k); },
    async getSigningKey(addr: string) { return signingKeyStore.get(addr) ?? null; },
    async removeSigningKey(addr: string) { signingKeyStore.delete(addr); },
    async clearSigningKeys() { signingKeyStore.clear(); },
    async exportPrivateStates(): Promise<PrivateStateExport> { throw new Error('Not implemented'); },
    async importPrivateStates() { throw new Error('Not implemented'); },
    async exportSigningKeys(): Promise<SigningKeyExport> { throw new Error('Not implemented'); },
    async importSigningKeys() { throw new Error('Not implemented'); },
  };
}

永続的な Node.js プライベート状態には、代わりに levelPrivateStateProvider を使用してください。


11) Testkit(統合テスト)

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

const logger = pino({ level: 'info' });
let testEnvironment: Awaited<ReturnType<typeof getTestEnvironment>>;

beforeAll(async () => {
  testEnvironment = getTestEnvironment(logger);
  const environmentConfig = await testEnvironment.start();
  // environmentConfig contains indexer, node, proofServer URLs
});

afterAll(async () => {
  await testEnvironment.shutdown();
});

// Get wallet providers for testing
const walletProvider = await testEnvironment.getMidnightWalletProvider();
// or multiple wallets (max 4 on local):
const [wallet1, wallet2] = await testEnvironment.startMidnightWalletProviders(2);

環境変数による環境の選択:

# Local Docker (default)
MN_TEST_ENVIRONMENT=undeployed yarn test

# Against preprod
MN_TEST_ENVIRONMENT=devnet yarn test

# Custom endpoints
MN_TEST_ENVIRONMENT=env-var-remote \
MN_TEST_NETWORK_ID=undeployed \
MN_TEST_INDEXER=http://localhost:8088/api/ \
MN_TEST_INDEXER_WS=ws://localhost:8088/ws/ \
MN_TEST_NODE=http://localhost:9944 \
yarn test

12) 証明サーバー

Node.js/ヘッドレスで使用する場合は、Docker 経由で証明サーバーをローカルで実行します。

# Auto-started proof server (preprod, pulls image automatically)
cd counter-cli && npm run preprod-ps

# Or manually
docker compose -f proof-server.yml up
# Wait for: "starting service... listening on: 0.0.0.0:6300"

# Direct Docker run
docker run -p 6300:6300 midnightntwrk/proof-server:latest midnight-proof-server -v

証明サーバーの URL:http://127.0.0.1:6300

Mac ARM(Apple Silicon)の修正方法: 証明サーバーが応答しなくなる場合は、Docker Desktop → Settings → General → Virtual Machine Options に移動し、Docker VMM を選択してから Docker を再起動します。


13) よくある落とし穴

setNetworkId が呼び出されていない → SDK の深い部分で不可解な型の不一致エラーが発生します。SDK の操作を行う前に、起動直後に呼び出してください。

Node.js で WebSocket がグローバルに設定されていない → ウォレット同期の GraphQL サブスクリプションが通知なく失敗します。エントリーファイルの先頭に globalThis.WebSocket = WebSocket を記述してください。

ZK アセットが見つからない → zkConfigPath が絶対パスで、コンパイル済みの managed フォルダーを指し、keys/ と zkir/ のサブディレクトリを含んでいることを再確認してください。開発前に sync:assets npm スクリプトを実行します。

「Failed to clone intent」 → ウォレット SDK のバグです。signTransactionIntents の回避策を使用してください。証明済みの UnboundTransaction のバランスを調整する際に発生します。SDK は 'pre-proof' をハードコードしていますが、intents には 'proof' データが含まれています。

デプロイ失敗後に DUST = 0 になる → 既知のウォレット SDK の問題です。DApp を再起動して、ロックされた DUST コインを解放してください。デプロイ前に DUST モニターを使用して状態を確認します。

Faucet 利用後にウォレットの残高が 0 → まず同期が完了するまで待ってください。それでも 0 の場合は、シールドアドレスではなく、非シールドアドレス(mn_addr_preprod1...)を使用したことを確認してください。

relayURL は WebSocket である必要がある → https:// を wss:// に、http:// を ws:// に変換します。ウォレット SDK はリレーに WebSocket URL を想定しています。

デプロイのたびに CompiledContract.make が呼び出される → デプロイ関数内ではなく、モジュールの読み込み時に一度だけ呼び出してください。毎回 ZK キーを読み込むと時間がかかります。

ブラウザーで levelPrivateStateProvider を使用している → LevelDB は Node.js 専用です。ブラウザー環境ではインメモリの createPrivateStateProvider を使用してください。

再コンパイル後も古いコントラクトアドレスを使用している → Compact コントラクトを変更すると検証鍵も変わります。古いアドレスでは証明の検証に失敗します。コントラクトを変更した場合は、必ず再デプロイしてください。


14) 依存関係のバージョン(スナップショット — 固定ではありません)

これらのバージョン番号は特定時点のスナップショットであり、変わる可能性があります。 インストール前に support matrix で現在テスト済みの組み合わせを確認してください。詳しくは references/volatile.md を参照してください。以下で重要なのはパッケージの 名前 です。@latest はインストールしないでください。

{
  "@midnight-ntwrk/compact-runtime": "0.15.0",
  "@midnight-ntwrk/ledger-v8": "8.0.3",
  "@midnight-ntwrk/midnight-js-contracts": "4.0.2",
  "@midnight-ntwrk/midnight-js-http-client-proof-provider": "4.0.2",
  "@midnight-ntwrk/midnight-js-indexer-public-data-provider": "4.0.2",
  "@midnight-ntwrk/midnight-js-level-private-state-provider": "4.0.2",
  "@midnight-ntwrk/midnight-js-network-id": "4.0.2",
  "@midnight-ntwrk/midnight-js-node-zk-config-provider": "4.0.2",
  "@midnight-ntwrk/midnight-js-types": "4.0.2",
  "@midnight-ntwrk/midnight-js-utils": "4.0.2",
  "@midnight-ntwrk/wallet-sdk-address-format": "3.1.0",
  "@midnight-ntwrk/wallet-sdk-dust-wallet": "3.0.0",
  "@midnight-ntwrk/wallet-sdk-facade": "3.0.0",
  "@midnight-ntwrk/wallet-sdk-hd": "3.0.1",
  "@midnight-ntwrk/wallet-sdk-shielded": "2.1.0",
  "@midnight-ntwrk/wallet-sdk-unshielded-wallet": "2.1.0",
  "@midnight-ntwrk/compact-js": "2.5.0"
}

Node.js のバージョン:22+(必須)

コメント