smithery/uvroxx

midnight-sdk-guide

TypeScript SDK integration guide for Midnight dApps. Use this skill when building frontends, connecting wallets, or calling contracts from TypeScript. Triggers on "SDK", "TypeScript", "wallet integration", "connect dApp", "call contract".

Installation

$ npx skills add smithery/uvroxx --skill midnight-sdk-guide

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/uvroxx.

npx skills add smithery/uvroxx

Browse all from smithery/uvroxx

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0
LicenseMIT
More metadata
author
webisoft
version
1.0.0
midnight-version
0.27.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,520 B
  • docs SUMMARY.md 264 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Midnight TypeScript SDK Quick Reference

Guide for integrating Midnight contracts with TypeScript applications.

When to Use

Reference this guide when:

  • Building a frontend for a Midnight dApp
  • Connecting the Lace wallet
  • Deploying or calling contracts from TypeScript
  • Handling errors from the SDK
  • Building transaction flows

Installation

npm install @midnight-ntwrk/midnight-js-contracts

Core Types

Contract Deployment

import { deployContract, ContractDeployment } from '@midnight-ntwrk/midnight-js-contracts';

const deployment: ContractDeployment = await deployContract({
  contract: compiledContract,
  privateState: initialPrivateState,
  args: constructorArgs,
});

const { contractAddress, initialState } = deployment;

Contract Interaction

import { callContract } from '@midnight-ntwrk/midnight-js-contracts';

// Call a circuit
const result = await callContract({
  contractAddress,
  circuitName: 'increment',
  args: [amount],
  privateState: currentPrivateState,
});

// Result contains new state and return value
const { newPrivateState, returnValue, proof } = result;

Providers

import {
  MidnightProvider,
  createMidnightProvider
} from '@midnight-ntwrk/midnight-js-contracts';

const provider = await createMidnightProvider({
  indexer: 'https://indexer.testnet.midnight.network',
  node: 'https://node.testnet.midnight.network',
  proofServer: 'https://prover.testnet.midnight.network',
});

State Management

interface ContractState<T> {
  publicState: PublicState;
  privateState: T;
}

// Subscribe to state changes
provider.subscribeToContract(contractAddress, (state) => {
  console.log('New state:', state);
});

Transaction Building

import { buildTransaction } from '@midnight-ntwrk/midnight-js-contracts';

const tx = await buildTransaction({
  contractAddress,
  circuitName: 'transfer',
  args: [recipient, amount],
  privateState,
});

// Sign and submit
const signedTx = await wallet.signTransaction(tx);
const txHash = await provider.submitTransaction(signedTx);

Wallet Integration

Browser Detection

declare global {
  interface Window {
    midnight?: {
      mnLace?: MidnightProvider;
    };
  }
}

function isWalletAvailable(): boolean {
  return typeof window !== 'undefined'
    && window.midnight?.mnLace !== undefined;
}

DApp Connector API

interface DAppConnectorAPI {
  enable(): Promise<MidnightAPI>;
  isEnabled(): Promise<boolean>;
  apiVersion(): string;
  name(): string;
  icon(): string;
}

async function connectWallet(): Promise<MidnightAPI> {
  if (!window.midnight?.mnLace) {
    throw new Error('Midnight Lace wallet not found');
  }
  return await window.midnight.mnLace.enable();
}

MidnightAPI Interface

interface MidnightAPI {
  getUsedAddresses(): Promise<string[]>;
  getBalance(): Promise<Balance>;
  signTx(tx: Transaction): Promise<SignedTransaction>;
  submitTx(signedTx: SignedTransaction): Promise<TxHash>;
  signData(address: string, payload: string): Promise<Signature>;
}

React Hook

export function useWallet() {
  const [state, setState] = useState({
    isConnected: false,
    address: null as string | null,
    isLoading: false,
    error: null as string | null,
  });

  const connect = useCallback(async () => {
    setState(prev => ({ ...prev, isLoading: true, error: null }));
    try {
      if (!window.midnight?.mnLace) {
        throw new Error('Please install Midnight Lace wallet');
      }
      const api = await window.midnight.mnLace.enable();
      const addresses = await api.getUsedAddresses();
      setState({
        isConnected: true,
        address: addresses[0] || null,
        isLoading: false,
        error: null,
      });
      return api;
    } catch (error) {
      setState(prev => ({
        ...prev,
        isLoading: false,
        error: error instanceof Error ? error.message : 'Failed',
      }));
      throw error;
    }
  }, []);

  return { ...state, connect };
}

Connection Flow

1. User clicks "Connect Wallet"
2. DApp calls window.midnight.mnLace.enable()
3. Wallet popup asks user to approve
4. User approves → DApp receives MidnightAPI
5. DApp can now interact with wallet

Error Handling

import { MidnightError, ContractError } from '@midnight-ntwrk/midnight-js-contracts';

try {
  await callContract({ ... });
} catch (error) {
  if (error instanceof ContractError) {
    console.error('Contract assertion failed:', error.message);
  } else if (error instanceof MidnightError) {
    console.error('Network error:', error.code);
  }
}

DApp Connector Errors

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

// ErrorCodes.Rejected - User rejected the request
// ErrorCodes.InvalidRequest - Malformed transaction or request
// ErrorCodes.InternalError - DApp connector couldn't process request

try {
  const api = await window.midnight.mnLace.enable();
} catch (error) {
  if (error.code === ErrorCodes.Rejected) {
    console.log('User rejected wallet connection');
  }
}

ContractTypeError

// Thrown when there's a contract type mismatch
try {
  const contract = await findDeployedContract(provider, address, MyContract);
} catch (e) {
  if (e instanceof ContractTypeError) {
    console.error('Contract type mismatch:', e.circuitIds);
  }
}

Private State Witnesses

TypeScript witnesses implement the Compact witness declarations:

// counter-witnesses.ts
import type { Witnesses } from './managed/counter';

export type CounterPrivateState = {
  localSecretKey: Uint8Array;
  storedValues: Map<string, bigint>;
};

export const createWitnesses = (
  state: CounterPrivateState
): Witnesses<CounterPrivateState> => ({
  local_secret_key: () => state.localSecretKey,

  store_secret_value: (value: bigint) => {
    state.storedValues.set('secret', value);
    return undefined; // returns []
  },

  get_secret_value: () => {
    return state.storedValues.get('secret') ?? 0n;
  },
});

export const createInitialState = (): CounterPrivateState => ({
  localSecretKey: crypto.getRandomValues(new Uint8Array(32)),
  storedValues: new Map(),
});

Best Practices

  1. Always check wallet availability before connecting
  2. Handle user rejection gracefully
  3. Store connection state in context/global state
  4. Provide clear loading/error feedback
  5. Test with Midnight Lace extension
  6. Keep private state secure - never log or expose it

Rules

See /rules/ directory for detailed documentation:

  • wallet-integration.md - Complete wallet integration patterns
  • error-handling.md - Error handling best practices

References