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

dynamic-midnight-wallet

DISABLED ON PLATFORM — skill file retained for future release. Do not surface in MIDSKILLS index until re-enabled. Scaffold a React + Vite app with Dynamic.xyz Midnight wallet connection via @dynamic-labs/midnight.

How do I install this agent skill?

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

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    The skill provides a standard and safe template for building a React application integrated with Dynamic.xyz's Midnight wallet, using official SDKs and following best practices.

  • Socketpass

    No alerts

  • Snykwarn

    Risk: MEDIUM · 1 issue

What does this agent skill do?

Dynamic Midnight Wallet Skill

This skill generates a complete React + Vite + TypeScript app that connects Midnight wallets through Dynamic.xyz (@dynamic-labs/midnight). It replaces hand-rolled window.midnight wiring with DynamicContextProvider, DynamicWidget, and typed Midnight wallet accessors.

Primary references:

  • dynamic.xyz/docs/react/wallets/using-wallets/midnight/using-midnight-wallets — injected 1AM extension
  • dynamic.xyz/docs/react/wallets/using-wallets/midnight/midnight-embedded-wallets — social/email MPC wallets
  • dynamic.xyz/docs/llms.txt — full Dynamic documentation index
  • @dynamic-labs/midnight@4.91.2 + @dynamic-labs/sdk-react-core@4.91.2 (pin together)

Key architecture notes:

  • A Midnight wallet is not a single address — it has three surfaces:
    SurfaceRoleDynamic API
    UnshieldedPublic address/statewallet.address
    ShieldedPrivate token poolwallet.additionalAddresses (MidnightShielded)
    DUSTFee-generation statewallet.additionalAddresses (MidnightDust)
  • NIGHT exists as both shielded and unshielded — different pools, not duplicate balances
  • Dynamic owns connection lifecycle, connectors, address/balance accessors, send routing
  • 1AM extension (injected) owns key custody, proving, signing, submission — Dynamic talks to it via @midnight-ntwrk/dapp-connector-api
  • Your app owns deposit UX — surface both unshielded and shielded addresses; DUST is generated, not deposited to
  • sendBalance routes by recipient prefix: mn_shield... → shielded pool, otherwise unshielded. No cross-pool transfers
  • Always guard with isMidnightWallet(wallet) before calling Midnight methods

Relationship to other skills:

  • Raw DApp Connector without Dynamic → react-wallet-connector/
  • Contract deploy + circuit calls via 1AM directly → 1am-wallet/
  • Embedded wallets only → see §17 in this skill (DynamicWaasMidnightConnectors)

1) Project Structure

my-dynamic-midnight-app/
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
├── vite.config.ts
├── .env.example
└── src/
    ├── main.tsx
    ├── App.tsx
    ├── MidnightWalletPanel.tsx
    ├── hooks/
    │   └── useMidnightWallet.ts
    └── vite-env.d.ts

2) Prerequisites

  • Node.js 18+
  • Dynamic.xyz account with Midnight enabled under Chains & Networks
  • Dynamic Environment ID from the dashboard
  • For injected flow: 1AM wallet browser extension installed
  • For embedded flow: enable Private Key Exports under Embedded Wallets → Security (required for MPC Midnight wallets)

3) Scaffold & Install

npm create vite@latest my-dynamic-midnight-app -- --template react-ts
cd my-dynamic-midnight-app
npm install @dynamic-labs/sdk-react-core@4.91.2 @dynamic-labs/midnight@4.91.2 @dynamic-labs/sdk-api-core@4.91.2

Create .env:

VITE_DYNAMIC_ENVIRONMENT_ID=your-environment-id-here

4) package.json

{
  "name": "my-dynamic-midnight-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@dynamic-labs/midnight": "4.91.2",
    "@dynamic-labs/sdk-api-core": "4.91.2",
    "@dynamic-labs/sdk-react-core": "4.91.2",
    "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 all @dynamic-labs/* packages to the same version. Check npm view @dynamic-labs/midnight version if install fails.


5) vite.config.ts

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

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

6) tsconfig.json / tsconfig.app.json / tsconfig.node.json

Use the standard Vite react-ts template configs (same as react-wallet-connector/SKILL.md §6–8).


7) src/vite-env.d.ts

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

interface ImportMetaEnv {
  readonly VITE_DYNAMIC_ENVIRONMENT_ID: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

8) 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>,
);

9) src/App.tsx

Injected 1AM extension flow (default template):

import { DynamicContextProvider, DynamicWidget } from '@dynamic-labs/sdk-react-core';
import { MidnightWalletConnectors } from '@dynamic-labs/midnight';
import MidnightWalletPanel from './MidnightWalletPanel';

const environmentId = import.meta.env.VITE_DYNAMIC_ENVIRONMENT_ID;

if (!environmentId) {
  throw new Error('Set VITE_DYNAMIC_ENVIRONMENT_ID in .env');
}

export default function App() {
  return (
    <DynamicContextProvider
      settings={{
        environmentId,
        walletConnectors: [MidnightWalletConnectors],
      }}
    >
      <header>
        <h1>Midnight + Dynamic</h1>
        <DynamicWidget />
      </header>
      <main>
        <MidnightWalletPanel />
      </main>
    </DynamicContextProvider>
  );
}

10) src/hooks/useMidnightWallet.ts

import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { isMidnightWallet } from '@dynamic-labs/midnight';
import { WalletAddressType } from '@dynamic-labs/sdk-api-core';

export function useMidnightWallet() {
  const { primaryWallet } = useDynamicContext();

  if (!primaryWallet || !isMidnightWallet(primaryWallet)) {
    return { wallet: null, isConnected: false as const };
  }

  const shieldedAddress = primaryWallet.additionalAddresses?.find(
    (a) => a.type === WalletAddressType.MidnightShielded,
  )?.address;

  const dustAddress = primaryWallet.additionalAddresses?.find(
    (a) => a.type === WalletAddressType.MidnightDust,
  )?.address;

  return {
    wallet: primaryWallet,
    isConnected: true as const,
    unshieldedAddress: primaryWallet.address,
    shieldedAddress,
    dustAddress,
  };
}

11) src/MidnightWalletPanel.tsx

Displays all three surfaces and balances. No CSS — add Tailwind or your preferred styling.

import { useCallback, useEffect, useState } from 'react';
import { useMidnightWallet } from './hooks/useMidnightWallet';

type Balances = {
  shieldedBalance?: string;
  unshieldedBalance?: string;
  dustBalance?: { balance: string; cap: string };
};

export default function MidnightWalletPanel() {
  const { wallet, isConnected, unshieldedAddress, shieldedAddress, dustAddress } =
    useMidnightWallet();
  const [balances, setBalances] = useState<Balances | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  const refreshBalances = useCallback(async () => {
    if (!wallet) return;
    setLoading(true);
    setError(null);
    try {
      const formatted = await wallet.getFormattedBalances();
      setBalances({
        shieldedBalance: formatted.shieldedBalance,
        unshieldedBalance: formatted.unshieldedBalance,
        dustBalance: formatted.dustBalance,
      });
    } catch (e) {
      setError(String(e));
    } finally {
      setLoading(false);
    }
  }, [wallet]);

  useEffect(() => {
    void refreshBalances();
  }, [refreshBalances]);

  if (!isConnected || !wallet) {
    return <p>Connect your Midnight wallet with the widget above.</p>;
  }

  return (
    <div>
      <h2>Wallet Surfaces</h2>
      <dl>
        <dt>Unshielded (public)</dt>
        <dd title={unshieldedAddress}>{unshieldedAddress}</dd>
        <dt>Shielded (private)</dt>
        <dd title={shieldedAddress ?? ''}>{shieldedAddress ?? '—'}</dd>
        <dt>DUST (fees)</dt>
        <dd title={dustAddress ?? ''}>{dustAddress ?? '—'}</dd>
      </dl>

      <h2>Balances</h2>
      {loading ? <p>Loading…</p> : null}
      {error ? <p role="alert">{error}</p> : null}
      {balances ? (
        <ul>
          <li>Unshielded NIGHT: {balances.unshieldedBalance ?? '0'}</li>
          <li>Shielded NIGHT: {balances.shieldedBalance ?? '0'}</li>
          <li>
            DUST:{' '}
            {balances.dustBalance
              ? `${balances.dustBalance.balance} / cap ${balances.dustBalance.cap}`
              : '—'}
          </li>
        </ul>
      ) : null}
      <button type="button" onClick={() => void refreshBalances()}>
        Refresh Balances
      </button>

      <h2>Deposit instructions</h2>
      <p>
        Send to the <strong>unshielded</strong> address for public NIGHT, or the{' '}
        <strong>shielded</strong> address for private NIGHT. DUST is generated from
        registered unshielded NIGHT — it is not deposited to directly.
      </p>
    </div>
  );
}

12) 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 + Dynamic</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

13) .env.example

VITE_DYNAMIC_ENVIRONMENT_ID=

14) Run

cp .env.example .env
# Paste your Dynamic Environment ID
npm install
npm run dev

Open http://localhost:5173. Click DynamicWidget → connect 1AM wallet → panel shows three surfaces and balances.


15) Checking Wallet Type

import { isMidnightWallet } from '@dynamic-labs/midnight';

if (!isMidnightWallet(wallet)) {
  throw new Error('This wallet is not a Midnight wallet');
}

Always narrow before calling getFormattedBalances(), sendBalance(), or connector methods.


16) Richer Shielded Handles (Connector API)

When circuits need coin/encryption public keys:

const connector = primaryWallet.connector;

const { shieldedAddress, shieldedCoinPublicKey, shieldedEncryptionPublicKey } =
  await connector.getShieldedAddresses();
const { unshieldedAddress } = await connector.getUnshieldedAddress();
const { dustAddress } = await connector.getDustAddress();

Use these when wiring 1am-wallet/ provider sessions on top of Dynamic.


17) Embedded Wallets (Social / Email)

Swap connector in App.tsx:

import { DynamicWaasMidnightConnectors } from '@dynamic-labs/midnight';

<DynamicContextProvider
  settings={{
    environmentId,
    walletConnectors: [DynamicWaasMidnightConnectors],
  }}
>

Dashboard requirements:

  1. Enable Midnight under Chains & Networks
  2. Enable Private Key Exports under Embedded Wallets → Security (403 on all ops if disabled)

Embedded balance shape differs slightly:

const { unshieldedBalance, shieldedTokenCount, dustBalance, dustSyncing } =
  await primaryWallet.getFormattedBalances();

// Poll until DUST sync completes (WaaS only)
if (dustSyncing) {
  setTimeout(() => void refreshBalances(), 2500);
}

Embedded-only extras: registerDust(), signMessage(), step-by-step createTransferTransaction → signTransaction → submitTransaction.


18) Sending Tokens

// Routes by recipient prefix — mn_shield... = shielded, else unshielded
await primaryWallet.sendBalance({
  toAddress: 'mn_shield...',
  amount: '1.5', // human-readable NIGHT for extension wallets
});

Cross-pool transfers are not supported. Sender and recipient must be in the same pool.

For raw per-token amounts:

const { shielded, unshielded, dust } = await primaryWallet.getBalances();

19) Ownership Boundaries

LayerOwns
DynamicConnection lifecycle, connectors, MidnightWallet object, address/balance accessors, send routing
1AM extensionKey custody, derivation, ZK proving, signing, submission
Your DAppDeposit/receive UX (show unshielded and shielded), which pool to display, DUST generation messaging

20) Troubleshooting

SymptomCauseFix
Midnight not in widgetChain disabledEnable Midnight in Dynamic dashboard → Chains & Networks
403 on all wallet methods (embedded)Private Key Exports offEnable under Embedded Wallets → Security
isMidnightWallet falseWrong connector or chainUse MidnightWalletConnectors or DynamicWaasMidnightConnectors
Shielded address missingWallet still syncingRetry after connect; poll dustSyncing for WaaS
Send fails cross-poolmn_addr → mn_shieldSame pool only — unshielded to unshielded, shielded to shielded
Version mismatch errorsMixed @dynamic-labs/* versionsPin all Dynamic packages to same version
Empty DUSTNIGHT not registeredCall registerDust() after funding unshielded NIGHT (embedded)

21) Agent Checklist

When generating this template for a user:

  • Scaffold Vite react-ts or write all files from this skill
  • Install @dynamic-labs/sdk-react-core, @dynamic-labs/midnight, @dynamic-labs/sdk-api-core at same version
  • Set VITE_DYNAMIC_ENVIRONMENT_ID in .env
  • Use MidnightWalletConnectors for extension (default) or DynamicWaasMidnightConnectors for embedded
  • Include DynamicWidget for connect/disconnect
  • Surface unshielded, shielded, and DUST in deposit UI
  • Guard all Midnight calls with isMidnightWallet
  • Omit CSS unless user requests styling
  • Link to 1am-wallet/ if user needs contract deploy on top of Dynamic connection

22) Related Skills

NeedSkill
DApp Connector without Dynamicreact-wallet-connector/
Contract deploy + circuits1am-wallet/
Token units & poolstoken-transfers/
Locker / payment vault dAppsexample-locker-dapp/, example-payment-dapp/

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/dynamic-midnight-wallet">View dynamic-midnight-wallet on skillZs</a>