> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Using Midnight embedded wallets

Embedded Midnight wallets are MPC wallets created from a user's social or email
login — no browser extension required. Like all Midnight wallets, they expose
**three surfaces**:

| Surface        | What it is                                                 | Where Dynamic exposes it                           |
| :------------- | :--------------------------------------------------------- | :------------------------------------------------- |
| **Unshielded** | Public address and state. The wallet's main address.       | `wallet.address`                                   |
| **Shielded**   | Private address and state. A separate token pool.          | `wallet.additionalAddresses` (`midnight_shielded`) |
| **DUST**       | Fee-generation state. DUST pays for Midnight transactions. | `wallet.additionalAddresses` (`midnight_dust`)     |

`NIGHT` exists as both a shielded and an unshielded asset — different token
types in different pools, not the same balance shown twice.

<Note>
  This page covers **embedded** Midnight wallets (created via social/email
  login). For wallets connected through the **injected 1am browser extension**,
  see [Using Midnight wallets](/react/wallets/using-wallets/midnight/using-midnight-wallets).
</Note>

## Enabling Midnight

<Steps>
  <Step title="Enable Midnight in the dashboard">
    Enable Midnight under [Chains & Networks](https://app.dynamic.xyz/dashboard/chains-and-networks).
  </Step>

  <Step title="Enable Private Key Exports in the dashboard">
    Midnight embedded wallets internally derive signing keys via the key export mechanism. **Private Key Exports must be enabled** in your environment settings or all wallet operations (balance reads, signing, transfers) will fail with a 403 error.

    Go to **Embedded Wallets → Security** in the [Dynamic dashboard](https://app.dynamic.xyz/dashboard/embedded-wallets) and toggle **Private Key Exports** on.

    <Warning>
      Without this setting enabled, Midnight wallets cannot initialise — calls to `getFormattedBalances()`, `signMessage()`, and all other wallet methods will fail.
    </Warning>
  </Step>

  <Step title="Install the connector">
    <CodeGroup>
      ```bash npm theme={"system"}
      npm i @dynamic-labs/midnight
      ```

      ```bash yarn theme={"system"}
      yarn add @dynamic-labs/midnight
      ```
    </CodeGroup>
  </Step>

  <Step title="Add the embedded connector to DynamicContextProvider">
    Use `DynamicWaasMidnightConnectors` for embedded (MPC) wallets.

    ```tsx React theme={"system"}
    import { DynamicContextProvider, DynamicWidget } from '@dynamic-labs/sdk-react-core';
    import { DynamicWaasMidnightConnectors } from '@dynamic-labs/midnight';

    const App = () => (
      <DynamicContextProvider
        settings={{
          environmentId: 'YOUR_ENVIRONMENT_ID',
          walletConnectors: [DynamicWaasMidnightConnectors],
        }}
      >
        <DynamicWidget />
      </DynamicContextProvider>
    );

    export default App;
    ```
  </Step>
</Steps>

## Getting a Midnight wallet

Narrow a wallet with `isMidnightWallet` before calling Midnight methods. The
guard both confirms the chain and gives you the typed wallet — all operations
below are called directly on it.

```tsx React theme={"system"}
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { isMidnightWallet } from '@dynamic-labs/midnight';

const { primaryWallet } = useDynamicContext();

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

// `primaryWallet` is now a typed Midnight wallet.
```

## Reading balances

`getFormattedBalances()` returns display-ready strings for all three surfaces in
one call:

```tsx React theme={"system"}
const { unshieldedBalance, shieldedTokenCount, dustBalance, dustSyncing } =
  await primaryWallet.getFormattedBalances();

// unshieldedBalance  -> unshielded NIGHT as a display string, e.g. "3.0" (undefined if none)
// shieldedTokenCount -> number of distinct token types with a positive shielded balance
//                       (shielded NIGHT is a separate token type from unshielded NIGHT)
// dustBalance        -> { balance: string, cap: string } (undefined if no DUST)
// dustSyncing        -> true while DUST is still syncing in the background (WaaS only)
```

Poll `dustSyncing` to know when all surfaces are ready:

```tsx React theme={"system"}
async function waitForSync() {
  const { dustSyncing } = await primaryWallet.getFormattedBalances();
  if (dustSyncing) {
    setTimeout(waitForSync, 2500); // retry until ready
  }
}
waitForSync();
```

Individual getters are also available:

```tsx React theme={"system"}
const shielded   = await primaryWallet.getShieldedBalance();   // string | undefined
const unshielded = await primaryWallet.getUnshieldedBalance(); // string | undefined
const dust       = await primaryWallet.getDustBalance();       // { balance: string, cap: string }
```

For raw, per-token amounts (a pool can hold more than just NIGHT), use
`getBalances()`, which returns `{ shielded, unshielded, dust }` keyed by token
type, with `bigint` values:

```tsx React theme={"system"}
const { shielded, unshielded, dust } = await primaryWallet.getBalances();
```

<Note>
  The first balance read on a device runs a one-time background sync (the DUST
  state can take a while to fold). Subsequent reads resume from a local
  checkpoint and return quickly.
</Note>

## Signing a message

```tsx React theme={"system"}
const signature = await primaryWallet.signMessage('Hello Midnight');
```

## Sending tokens

Embedded Midnight wallets support both **unshielded** (public) and **shielded**
(private) transfers for NIGHT and other tokens. Amounts are in the token's
smallest (atomic) unit unless `token.decimals` is set.

### Simple send

`sendBalance` builds, proves, and broadcasts in one call, and routes to the
right pool automatically based on the recipient prefix (`mn_shield…` →
shielded, otherwise unshielded). It returns the transaction hash.

```tsx React theme={"system"}
// Unshielded NIGHT transfer
const txHash = await primaryWallet.sendBalance({
  toAddress: 'mn_addr...',
  amount: '100000000', // atomic units
});

// Shielded NIGHT transfer — same call, shielded recipient
await primaryWallet.sendBalance({
  toAddress: 'mn_shield...',
  amount: '100000000',
});

// Shielded transfer of a non-NIGHT token
await primaryWallet.sendBalance({
  toAddress: 'mn_shield...',
  amount: '50',
  token: {
    address: 'tokenTypeHex', // token type identifier
    decimals: 6,             // optional, defaults to 0
  },
});
```

<Note>
  `sendBalance` routes based on the recipient address prefix: `mn_addr` draws
  from the unshielded pool; `mn_shield` draws from the shielded pool. Cross-pool
  transfers (unshielded → shielded or vice versa) are not supported.

  The optional `token` parameter lets you send tokens other than native NIGHT.
  Pass `token.address` with the token type identifier and `token.decimals` if
  the amount needs decimal conversion. Omit `token` entirely for NIGHT transfers.
</Note>

### Step-by-step send

For more control, run the three steps yourself — **build → sign → submit**.
This lets you inspect or persist the serialized transaction between steps. Set
`type` to `'unshielded'` or `'shielded'` per transfer.

```tsx React theme={"system"}
// 1. Build an unsigned transaction.
const { serializedTransaction } = await primaryWallet.createTransferTransaction({
  transfers: [
    {
      type: 'unshielded',       // or 'shielded'
      recipientAddress: 'mn_addr...',
      amount: '100000000',      // atomic units
      tokenType: 'tokenTypeHex', // optional — omit for native NIGHT
    },
  ],
});

// 2. Sign + ZK-prove (unshielded segments are MPC-signed; shielded/dust are proven).
const finalizedTransaction =
  await primaryWallet.signTransaction(serializedTransaction);

// 3. Broadcast.
const { txHash } = await primaryWallet.submitTransaction(finalizedTransaction);
```

<Note>
  Transactions are paid for in **DUST**, generated by registered unshielded
  NIGHT. If a wallet has no DUST, register it first (see below).
</Note>

## Registering for DUST

DUST is the resource that pays for Midnight transactions. It is generated over
time by unshielded NIGHT that has been registered for generation. Call
`registerDust()` once to designate the wallet's NIGHT for DUST generation.

```tsx React theme={"system"}
const result = await primaryWallet.registerDust();
// result.status -> 'registered' | 'already_registered' | 'already_has_dust' | 'no_utxos'
```

<Tip>
  Fund the wallet with unshielded NIGHT before registering — DUST is generated
  from NIGHT UTxOs, so a wallet with no NIGHT has nothing to register.
</Tip>

## Recovering reserved UTxOs

If a transaction is built or signed but never submitted, its inputs stay
reserved. These methods release them:

```tsx React theme={"system"}
// Release the inputs of a specific built/signed transaction.
await primaryWallet.revertTransaction(serializedTransaction);

// Release every finalized-but-unsubmitted transaction the wallet knows about.
await primaryWallet.revertAllPending();
```

<Warning>
  `resetWalletCache()` is a last resort. It clears the wallet's persisted state
  and forces a full cold re-sync on the next operation. Use it only when inputs
  stay stuck after `revertTransaction` and `revertAllPending`.

  ```tsx React theme={"system"}
  await primaryWallet.resetWalletCache();
  ```
</Warning>

## Resources

* [Enabling Chains & Networks](/react/chains/enabling-chains)
* [Using Midnight wallets (injected 1am extension)](/react/wallets/using-wallets/midnight/using-midnight-wallets)
