skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
kali-decoder/midnight-skills124 installs

react-wallet-connector

Generate a React + Vite TypeScript app that connects to a Midnight wallet via the DApp Connector API (@midnight-ntwrk/dapp-connector-api). Use when building a React frontend, bootstrapping a wallet connector, wiring connect/disconnect UI, reading window.midnight wallets, getting unshielded addresses, or asking about the DApp Connector API connection flow. Produces a minimal runnable template — styling is intentionally omitted so the user can add Tailwind, CSS modules, etc.

How do I install this agent skill?

npx skills add https://github.com/kali-decoder/midnight-skills --skill react-wallet-connector
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill provides a standard template for building a React application that integrates with Midnight blockchain wallets. It adheres to official documentation for wallet connectivity and proactively includes security best practices for handling untrusted data from wallet extensions.

  • Socketpass

    No alerts

  • Snykwarn

    Risk: MEDIUM · 1 issue

What does this agent skill do?

React Wallet Connector Skill

This skill generates a complete, runnable React application that connects to a Midnight wallet extension using the DApp Connector API. It covers every file needed: Vite + React + TypeScript scaffold, wallet selection, connection logic, and a WalletCard UI component.

Primary references:

  • docs.midnight.network — React wallet connector guide (DApp Connector API)
  • llms.txt — full Midnight documentation index
  • @midnight-ntwrk/dapp-connector-api@4.0.1 — latest stable connector package (Feb 2026)

Key architecture notes:

  • Wallets inject InitialAPI instances on window.midnight, each keyed by a UUID — never use hardcoded keys like window.midnight.mnLace
  • Enumerate wallets with Object.values(window.midnight); when multiple wallets exist, let the user choose
  • Import @midnight-ntwrk/dapp-connector-api as a side effect to augment global window.midnight types
  • Request the shielded address only when your app actually needs it; the template uses getUnshieldedAddress()
  • Network IDs: 'undeployed' (local), 'preview', 'preprod', 'mainnet' — must match the wallet's configured network
  • Code examples omit CSS styling by design; add your preferred styling solution after scaffolding

Relationship to other skills:

  • For full contract deploy + circuit calls via 1AM wallet → use 1am-wallet/
  • For headless Node.js wallet + tests → use example-hello-world/ or midnight-js/
  • This skill is the frontend wallet connection foundation only

1) Project Structure

my-wallet-app/
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
├── vite.config.ts
└── src/
    ├── main.tsx
    ├── App.tsx
    ├── WalletCard.tsx
    ├── types.ts
    ├── selectWallet.ts
    └── vite-env.d.ts

2) Prerequisites

  • Node.js 18+ and npm
  • Basic React + TypeScript familiarity
  • A Midnight wallet browser extension installed (1AM, Lace, or any DApp Connector–compatible wallet)

3) Scaffold & Install

npm create vite@latest my-wallet-app -- --template react-ts
cd my-wallet-app
npm install @midnight-ntwrk/dapp-connector-api@4.0.1

4) package.json

Use the Vite react-ts template output and ensure @midnight-ntwrk/dapp-connector-api is listed:

{
  "name": "my-wallet-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@midnight-ntwrk/dapp-connector-api": "4.0.1",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@types/react": "^19.0.0",
    "@types/react-dom": "^19.0.0",
    "@vitejs/plugin-react": "^4.3.0",
    "typescript": "~5.7.0",
    "vite": "^6.0.0"
  }
}

Pin @midnight-ntwrk/dapp-connector-api to 4.0.1 unless the user specifies otherwise. Check npm view @midnight-ntwrk/dapp-connector-api version if install fails with ETARGET.


5) vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
});

6) tsconfig.json

{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ]
}

7) tsconfig.app.json

{
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true
  },
  "include": ["src"]
}

8) tsconfig.node.json

{
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
    "target": "ES2022",
    "lib": ["ES2023"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true
  },
  "include": ["vite.config.ts"]
}

9) src/vite-env.d.ts

/// <reference types="vite/client" />

The @midnight-ntwrk/dapp-connector-api side-effect import in App.tsx augments window.midnight — no manual declaration needed.


10) src/types.ts

export interface WalletCardProps {
  isConnected: boolean;
  walletAddress: string | null;
  onConnect: () => void;
  onDisconnect: () => void;
}

11) src/selectWallet.ts

Wallets inject under window.midnight with UUID keys. Always enumerate — never hardcode a wallet name.

import type { InitialAPI } from '@midnight-ntwrk/dapp-connector-api';

export const listWallets = (): InitialAPI[] => {
  const injected = window.midnight;
  return injected ? Object.values(injected) : [];
};

export const selectWallet = (): InitialAPI => {
  const wallets = listWallets();

  if (wallets.length === 0) {
    throw new Error(
      'No Midnight wallet found. Please install a Midnight wallet extension.',
    );
  }

  return wallets[0];
};

When more than one wallet is available, render a picker using listWallets() and let the user choose. Display each wallet's name and icon safely to prevent XSS.


12) src/WalletCard.tsx

Presentation layer — connection status, address display, connect/disconnect buttons. No CSS included; add styling as needed.

import React from 'react';
import type { WalletCardProps } from './types';

const WalletCard: React.FC<WalletCardProps> = ({
  isConnected,
  walletAddress,
  onConnect,
  onDisconnect,
}) => {
  return (
    <div>
      <div>
        <h2>Connection Status</h2>
        <div>{isConnected ? 'Connected' : 'Disconnected'}</div>
      </div>

      <div>
        {isConnected && walletAddress ? (
          <>
            <p>Wallet Address:</p>
            <p title={walletAddress}>{walletAddress}</p>
          </>
        ) : (
          <p>Please connect your wallet to proceed.</p>
        )}
      </div>

      <div>
        {isConnected ? (
          <button onClick={onDisconnect}>Disconnect Wallet</button>
        ) : (
          <button onClick={onConnect}>Connect Wallet</button>
        )}
      </div>
    </div>
  );
};

export default WalletCard;

13) src/App.tsx

Connection logic using the DApp Connector API.

import React, { useState } from 'react';
import WalletCard from './WalletCard';
import '@midnight-ntwrk/dapp-connector-api';
import { selectWallet } from './selectWallet';

const App: React.FC = () => {
  const [isConnected, setIsConnected] = useState<boolean>(false);
  const [walletAddress, setWalletAddress] = useState<string | null>(null);

  const handleConnect = async () => {
    console.log('Connect button clicked');
    let connected = false;
    let address: string | null = null;

    try {
      const wallet = selectWallet();

      // 'undeployed' for local dev; 'preprod' | 'preview' | 'mainnet' for live networks
      const connectedApi = await wallet.connect('preprod');

      const { unshieldedAddress } = await connectedApi.getUnshieldedAddress();
      address = unshieldedAddress;

      const serviceUriConfig = await connectedApi.getConfiguration();
      console.log('Service URI Config:', serviceUriConfig);

      const connectionStatus = await connectedApi.getConnectionStatus();
      if (connectionStatus.status === 'connected') {
        connected = true;
        console.log('Connected to the wallet:', address);
      }
    } catch (error) {
      console.log('An error occurred:', error);
    }

    setIsConnected(connected);
    setWalletAddress(address);
  };

  const handleDisconnect = () => {
    setWalletAddress(null);
    setIsConnected(false);
  };

  return (
    <div>
      <header>
        <h1>Midnight Wallet Connector</h1>
      </header>
      <main>
        <WalletCard
          isConnected={isConnected}
          walletAddress={walletAddress}
          onConnect={handleConnect}
          onDisconnect={handleDisconnect}
        />
      </main>
    </div>
  );
};

export default App;

Connection flow breakdown

  1. Select wallet — selectWallet() reads window.midnight entries; throws if none found (caught by try/catch)
  2. Connect to network — wallet.connect(networkId) prompts the user to authorize
  3. Retrieve address — getUnshieldedAddress() returns the public unshielded address
  4. Check status — getConnectionStatus() resolves to { status: 'connected' | 'disconnected' }
  5. Optional config — getConfiguration() returns service URIs (indexer, node, etc.) for downstream SDK wiring

14) src/main.tsx

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

15) index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Midnight Wallet Connector</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

16) Run

npm install
npm run dev

Open http://localhost:5173. Click Connect Wallet — the extension prompts for authorization. After approval, the app shows connection status and the unshielded address.


17) Multi-Wallet Picker (Optional Enhancement)

When listWallets() returns more than one entry, replace selectWallet() auto-pick with a user-facing selector:

// src/WalletPicker.tsx
import type { InitialAPI } from '@midnight-ntwrk/dapp-connector-api';
import { listWallets } from './selectWallet';

type Props = {
  onSelect: (wallet: InitialAPI) => void;
};

export function WalletPicker({ onSelect }: Props) {
  const wallets = listWallets();

  if (wallets.length === 0) {
    return <p>No Midnight wallet found. Install a wallet extension and refresh.</p>;
  }

  return (
    <ul>
      {wallets.map((wallet) => (
        <li key={wallet.name}>
          <button type="button" onClick={() => onSelect(wallet)}>
            {wallet.name}
          </button>
        </li>
      ))}
    </ul>
  );
}

Render wallet name and icon as text only unless you sanitize HTML. Never use dangerouslySetInnerHTML for wallet-provided icon URLs.


18) Troubleshooting

ErrorCauseFix
window.midnight is undefinedNo extension installed or page loaded before injectionInstall a Midnight wallet; refresh after install
No Midnight wallet foundExtension disabled or wrong detection patternUse Object.values(window.midnight) — not window.midnight.mnLace or other hardcoded keys
Connection rejected / failsNetwork mismatchEnsure connect('preprod') matches the wallet's active network
Connection hangsWallet locked or not syncedUnlock wallet; wait for sync
ETARGET on installStale package versionRun npm view @midnight-ntwrk/dapp-connector-api version and pin the latest
Type errors on window.midnightMissing side-effect importAdd import '@midnight-ntwrk/dapp-connector-api' in App.tsx

19) Next Steps

After a working connector, extend the app:

FeatureSkill / API
Deploy & call Compact contracts1am-wallet/
Token transferstoken-transfers/
Query balances & tx historyindexer/
Sign arbitrary messagesconnectedApi signing methods (see DApp Connector API docs)
Multi-network selectorNetwork dropdown calling wallet.connect(selectedNetwork)
Full SDK provider wiringmidnight-js/

20) Agent Checklist

When generating this template for a user:

  • Scaffold with Vite react-ts or write all files from this skill
  • Install @midnight-ntwrk/dapp-connector-api@4.0.1
  • Create types.ts, selectWallet.ts, WalletCard.tsx, App.tsx, main.tsx
  • Include side-effect import @midnight-ntwrk/dapp-connector-api in App.tsx
  • Use Object.values(window.midnight) for wallet detection — never hardcode wallet keys
  • Default network to 'preprod' unless user specifies local ('undeployed') or other network
  • Omit CSS unless the user requests styling
  • Mention wallet extension must be installed before testing

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/kali-decoder/midnight-skills/react-wallet-connector">View react-wallet-connector on skillZs</a>