AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Midnight Dapp Dev

skill-mzf11125-midnight-agent-skills-midnight-dapp-dev · by mzf11125

Comprehensive guide for Midnight Network DApp frontend development covering project scaffolding with Vite and React 19 plus shadcn/ui templates, Next.js wallet connector patterns via the DApp Connector API with App Router, React wallet connector with Vite setup, provider architecture including MidnightProviders, proof provider, public data provider, private state provider, wallet provider, and ZK…

No reviews yet
0 installs
23 views
0.0% view→install

Install

$ agentstack add skill-mzf11125-midnight-agent-skills-midnight-dapp-dev

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-mzf11125-midnight-agent-skills-midnight-dapp-dev)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Midnight Dapp Dev? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Midnight DApp Development

Overview

Midnight DApp frontend development involves building web applications that interact with the Midnight Network blockchain using TypeScript and React. This guide covers the complete workflow from project scaffolding to production deployment. The Midnight ecosystem provides several TypeScript packages that enable wallet connections, contract interactions, state management, and ZK proof generation all from within a browser or Node.js application.

The core development pattern follows a provider based architecture where each concern such as wallet connectivity, proof generation, or state management is handled by a dedicated provider. These providers are composed together using the MidnightProviders abstraction which serves as the backbone of any Midnight DApp.

Developers typically use either Vite with React 19 for single page applications or Next.js with the App Router for server rendered applications. Both approaches support the full Midnight DApp Connector API for wallet integration.

Project Scaffolding Patterns

Vite Plus React 19 Plus shadcn/ui

The recommended Vite scaffolding pattern combines React 19 with TypeScript and shadcn/ui for building Midnight DApps. Start by creating a Vite project with React and TypeScript support.

npm create vite@latest my-midnight-dapp -- --template react-ts
cd my-midnight-dapp
npm install

Add the Midnight dependencies needed for a standard DApp frontend. The core packages include the DApp Connector for wallet integration and the various providers for state management and contract interaction.

npm install @midnight-ntwrk/dapp-connector-api
npm install @midnight-ntwrk/onchain-rpc-provider
npm install @midnight-ntwrk/midnight-js-types
npm install @midnight-ntwrk/midnight-js-contracts
npm install @midnight-ntwrk/midnight-js-level-private-state-provider
npm install @midnight-ntwrk/midnight-js-network-id
npm install @midnight-ntwrk/midnight-js-fetch-zk-config-provider
npm install @midnight-ntwrk/midnight-js-http-client-proof-provider

Install shadcn/ui following the standard CLI initialization. This requires tailwindcss and its associated configuration.

npx shadcn@latest init
npx shadcn@latest add button card input toast dialog

The project structure for a Midnight DApp should organize concerns clearly. Create directories for components, hooks, providers, contracts, and utilities.

src/
  components/
    wallet/
      ConnectButton.tsx
      WalletStatus.tsx
      BalanceDisplay.tsx
    contract/
      ContractForm.tsx
      TransactionResult.tsx
    layout/
      AppLayout.tsx
      Header.tsx
  hooks/
    useWallet.ts
    useContract.ts
    useMidnightProviders.ts
  providers/
    MidnightProviders.tsx
    wallet.ts
    proof.ts
    state.ts
  contracts/
    types.ts
    interaction.ts
  lib/
    midnight.ts
    utils.ts
  App.tsx
  main.tsx

Next.js Wallet Connector

Next.js projects use the App Router pattern for Midnight DApp development. Create a Next.js application with TypeScript and the App Router enabled.

npx create-next-app@latest my-midnight-dapp --typescript --tailwind --app
cd my-midnight-dapp

Install the Midnight dependencies alongside the standard Next.js packages.

npm install @midnight-ntwrk/dapp-connector-api
npm install @midnight-ntwrk/midnight-js-types
npm install @midnight-ntwrk/midnight-js-contracts
npm install @midnight-ntwrk/midnight-js-level-private-state-provider
npm install @midnight-ntwrk/midnight-js-network-id
npm install @midnight-ntwrk/midnight-js-fetch-zk-config-provider
npm install @midnight-ntwrk/midnight-js-http-client-proof-provider

The App Router pattern for Midnight DApps requires careful handling of client side only components. The wallet connector and all blockchain interactions must run in the browser since they depend on the window.midnight API. Use the 'use client' directive at the top of any file that interacts with the Midnight provider stack.

For the layout pattern create a root layout with metadata and a client side provider wrapper. The providers must be initialized in a client component and wrap the application at the layout level.

src/
  app/
    layout.tsx
    page.tsx
    providers.tsx
  components/
    wallet/
      ConnectButton.tsx
      WalletStatus.tsx
    contract/
      ContractForm.tsx
      TransactionResult.tsx
    ui/
      Button.tsx
      Card.tsx
      Input.tsx
  hooks/
    useWallet.ts
    useContract.ts
  lib/
    midnight.ts
    providers.ts

React Wallet Connector With Vite

For projects that do not need Next.js features a simpler Vite plus React setup provides a lightweight alternative. This is suitable for single page DApps that do not require server side rendering.

npm create vite@latest my-midnight-dapp -- --template react-ts
cd my-midnight-dapp
npm install
npm install @midnight-ntwrk/dapp-connector-api @midnight-ntwrk/midnight-js-types

Wallet connection in a Vite React app follows the same DApp Connector API patterns. The initialization code checks for the window.midnight object and uses the connector API to establish a connection.

import { useEffect, useState } from 'react';
import {
  type ConnectedAPI,
  type ConnectionStatus,
  DAppConnectorAPI
} from '@midnight-ntwrk/dapp-connector-api';

function useMidnightWallet() {
  const [api, setApi] = useState(null);
  const [status, setStatus] = useState('disconnected');

  useEffect(() => {
    const midnight = window.midnight;
    if (!midnight) {
      setStatus('unavailable');
      return;
    }

    const connector = new DAppConnectorAPI(midnight);
    connector.connect().then((connectedApi) => {
      setApi(connectedApi);
      setStatus('connected');
    });

    return () => {
      connector.disconnect();
    };
  }, []);

  return { api, status };
}

Provider Architecture

MidnightProviders

The MidnightProviders abstraction is the central composition point for all provider services in a Midnight DApp. It combines the wallet provider, proof provider, public data provider, private state provider, and ZK config provider into a single interface that contracts consume.

The MidnightProviders type is generic over three parameters. The first parameter is the public state type which varies per contract. The second parameter is the wallet provider type. The third parameter is the private state type which can be void if the contract has no private state.

type MidnightProviders = {
  readonly publicDataProvider: PublicDataProvider;
  readonly privateStateProvider: PrivateStateProvider;
  readonly walletProvider: W;
  readonly zkConfigProvider: ZKConfigProvider;
};

Building a MidnightProviders instance involves initializing each provider component and composing them together. The wallet provider comes from the DApp Connector connection. The public data provider wraps the indexer GraphQL endpoint. The private state provider manages encrypted local storage. The ZK config provider fetches circuit configuration from the network.

async function buildProviders(walletAPI: ConnectedAPI): Promise> {
  const walletProvider = new WalletProviderAdapter(walletAPI);
  const publicDataProvider = new IndexerPublicDataProvider(indexerUri);
  const privateStateProvider = await LevelPrivateStateProvider.create({
    privateStateStoreName: 'my-dapp-state'
  });
  const zkConfigProvider = new FetchZkConfigProvider(
    walletAPI.zkConfigUri,
    fetch
  );

  return {
    publicDataProvider,
    privateStateProvider,
    walletProvider,
    zkConfigProvider
  };
}

Proof Provider

The proof provider handles zero knowledge proof generation for contract calls. There are two primary proof provider implementations available to DApp developers.

The DApp Connector Proof Provider relies on the browser wallet extension to generate proofs client side. This is the standard approach for end user applications where the wallet handles proving transparently.

const proofProvider = new DAppConnectorProofProvider(connectedAPI);

The HTTP Client Proof Provider sends proving requests to a remote proof server. This is useful for server side proving or when the wallet does not support a particular proving scheme.

const proofProvider = new HttpClientProofProvider(
  'https://proof-server.example.com',
  fetch
);

Public Data Provider

The public data provider serves as the read interface to the Midnight blockchain. It wraps the GraphQL indexer API and provides typed access to contract state, transactions, and block data. All public state queries flow through this provider.

const publicDataProvider = new IndexerPublicDataProvider(
  'https://indexer.preview.midnight.network/api/v1/graphql',
  { contractAddress }
);

Private State Provider

The private state provider uses level based encrypted local storage to persist sensitive contract state that must remain hidden from the public ledger. It supports password rotation for key updates and multiple crypto backends for flexibility.

const privateStateProvider = await LevelPrivateStateProvider.create({
  privateStateStoreName: 'my-app-private-state'
});

Wallet Provider

The wallet provider wraps the DApp Connector connection and exposes wallet operations such as token transfers, balance queries, and key material access. It serves as the bridge between the DApp and the user's wallet.

ZK Config Provider

The ZK config provider fetches zero knowledge circuit configuration from the network. This configuration includes circuit parameters, proof types, and verification keys needed for proof generation and verification.

const zkConfigProvider = new FetchZkConfigProvider(
  zkConfigUri,
  fetch
);

Wallet Integration

DApp Connector API v4.0.1

The DApp Connector API is the standard interface for DApps to interact with Midnight wallets. It is accessed through the window.midnight global object which is injected by wallet browser extensions such as 1AM and Lace.

The DApp Connector API provides methods for connecting to a wallet, disconnecting, requesting authorization, and accessing the connected wallet interface. The connected wallet interface exposes methods for contract deployment, contract calls, token operations, and key material access.

const midnight = window.midnight;
if (!midnight) {
  throw new Error('No Midnight wallet extension detected');
}

const initialApi = await midnight.connect();
const connectedApi = await initialApi.requestAuthorization({
  networkId: NetworkId.Preprod
});

The connection status can be one of several states including 'disconnected', 'connecting', 'connected', or 'unavailable'. DApps should monitor the connection status and update their UI accordingly.

Connect and Disconnect

Connecting to a wallet is an asynchronous operation that may require user approval. The connect method returns an initial API object that has not yet been authorized for network access.

async function connectWallet(): Promise {
  const midnight = window.midnight;
  const initialApi = await midnight.connect();
  const connectedApi = await initialApi.requestAuthorization();
  return connectedApi;
}

Disconnecting releases the wallet connection and clears any stored state on the DApp side. The wallet remains available for reconnection.

async function disconnectWallet(api: ConnectedAPI): Promise {
  await api.disconnect();
}

Request Authorization

The request authorization step is where the DApp asks the user to approve network access. This step may present a wallet dialog to the user showing the requested network and permissions.

const connectedApi = await initialApi.requestAuthorization({
  networkId: NetworkId.Preprod
});

DApp Connector Types

Configuration

The Configuration type defines the settings for a DApp Connector instance. It includes the network identifier and optional proving server configuration.

type Configuration = {
  readonly networkId: NetworkId;
};

ConnectionStatus

The ConnectionStatus type tracks the current state of the wallet connection. It is a union of string literal types representing each possible connection state.

type ConnectionStatus =
  | 'disconnected'
  | 'connecting'
  | 'connected'
  | 'disconnecting'
  | 'unavailable';

ConnectedAPI

The ConnectedAPI interface represents a fully authorized wallet connection. It exposes all methods needed for contract deployment, contract calls, token operations, and provider access.

interface ConnectedAPI {
  readonly deployContract: (args: DeployArgs) => Promise;
  readonly submitCallTx: (args: CallTxArgs) => Promise;
  readonly getBalances: () => Promise;
  readonly getUtxos: () => Promise;
  readonly disconnect: () => Promise;
  readonly networkId: NetworkId;
  readonly walletAddress: string;
  readonly proveTransaction: (tx: UnprovenTransaction) => Promise;
  readonly waitForTxFinalization: (txHash: string) => Promise;
}

InitialAPI

The InitialAPI is returned from the connect call before authorization. It provides a limited interface for requesting authorization and checking connection state.

interface InitialAPI {
  readonly requestAuthorization: (config?: Configuration) => Promise;
  readonly connectionStatus: ConnectionStatus;
}

WalletConnectedAPI

The WalletConnectedAPI extends ConnectedAPI with wallet specific operations such as key material access and signing.

interface WalletConnectedAPI extends ConnectedAPI {
  readonly keyMaterialProvider: KeyMaterialProvider;
  readonly provingProvider: ProvingProvider;
}

KeyMaterialProvider

The KeyMaterialProvider gives DApps access to the wallet key material without exposing raw private keys. It provides derived keys for specific purposes such as encryption or signing.

interface KeyMaterialProvider {
  readonly getEncryptionPublicKey: () => Promise;
  readonly getSigningPublicKey: () => Promise;
  readonly signData: (data: Uint8Array) => Promise;
}

ProvingProvider

The ProvingProvider handles zero knowledge proof generation using the wallet key material. It takes an unproven transaction and returns a proven transaction ready for submission.

interface ProvingProvider {
  readonly proveTransaction: (
    tx: UnprovenTransaction,
    zkConfig: ZkConfig
  ) => Promise;
}

Transaction Flow

Creating an Unproven Transaction

An unproven transaction contains all the public inputs and circuit context needed for a contract call but lacks the zero knowledge proof. It is created using the contract type definitions and the provider stack.

const unprovenTx = await contractInterface.createUnprovenCallTx(
  providers,
  'increment'
);

Proving the Transaction

Proving generates the zero knowledge proof that attests to the validity of the transaction without revealing private inputs. The proof provider handles this step using either the browser wallet or a remote proof server.

const provenTx = await contractInterface.proveCallTx(
  providers,
  unprovenTx
);

Submitting the Transaction

Submission sends the proven transaction to the Midnight network. The transaction is broadcast to the mempool and included in a forthcoming block.

const txHash = await contractInterface.submitCallTx(
  providers,
  provenTx
);

Waiting for Finalization

After submission the DApp should wait for the transaction to be finalized. Finalization means the transaction has been included in a block and is considered irreversible.

const result = await contractInterface.waitForCallTxFinalization(
  providers,
  txHash
);

Handling Transaction Results

Transaction re

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.