dynamic-midnight-wallet
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDynamic Midnight Wallet Skill
Dynamic Midnight钱包技能
This skill generates a complete React + Vite + TypeScript app that connects Midnight wallets through Dynamic.xyz (). It replaces hand-rolled wiring with , , and typed Midnight wallet accessors.
@dynamic-labs/midnightwindow.midnightDynamicContextProviderDynamicWidgetPrimary references:
- — injected 1AM extension
dynamic.xyz/docs/react/wallets/using-wallets/midnight/using-midnight-wallets - — social/email MPC wallets
dynamic.xyz/docs/react/wallets/using-wallets/midnight/midnight-embedded-wallets - — full Dynamic documentation index
dynamic.xyz/docs/llms.txt - +
@dynamic-labs/midnight@4.91.2(pin together)@dynamic-labs/sdk-react-core@4.91.2
Key architecture notes:
- A Midnight wallet is not a single address — it has three surfaces:
Surface Role Dynamic API Unshielded Public address/state wallet.addressShielded Private token pool (wallet.additionalAddresses)MidnightShieldedDUST Fee-generation state (wallet.additionalAddresses)MidnightDust - exists as both shielded and unshielded — different pools, not duplicate balances
NIGHT - 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
- routes by recipient prefix:
sendBalance→ shielded pool, otherwise unshielded. No cross-pool transfersmn_shield... - Always guard with before calling Midnight methods
isMidnightWallet(wallet)
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
本技能可生成完整的React + Vite + TypeScript应用,通过Dynamic.xyz()连接Midnight钱包。它使用、和类型化Midnight钱包访问器替代手动编写的连接逻辑。
@dynamic-labs/midnightDynamicContextProviderDynamicWidgetwindow.midnight主要参考资料:
- — 注入式1AM扩展
dynamic.xyz/docs/react/wallets/using-wallets/midnight/using-midnight-wallets - — 社交/邮箱MPC钱包
dynamic.xyz/docs/react/wallets/using-wallets/midnight/midnight-embedded-wallets - — Dynamic完整文档索引
dynamic.xyz/docs/llms.txt - +
@dynamic-labs/midnight@4.91.2(需锁定同一版本)@dynamic-labs/sdk-react-core@4.91.2
核心架构说明:
- Midnight钱包并非单一地址——它拥有三种交互层面:
层面 作用 Dynamic API Unshielded(未屏蔽) 公开地址/状态 wallet.addressShielded(已屏蔽) 私有代币池 (wallet.additionalAddresses类型)MidnightShieldedDUST 手续费生成状态 (wallet.additionalAddresses类型)MidnightDust - 代币同时存在于已屏蔽和未屏蔽池中——是不同的资金池,而非重复余额
NIGHT - Dynamic负责连接生命周期、连接器、地址/余额访问器、转账路由
- 1AM扩展(注入式)负责密钥托管、零知识证明、签名、交易提交——Dynamic通过与其通信
@midnight-ntwrk/dapp-connector-api - 你的应用负责存款用户体验——需展示未屏蔽和已屏蔽两种地址;DUST由系统生成,无需直接存款
- 根据接收方前缀路由:
sendBalance→ 已屏蔽池,其他则为未屏蔽池。不支持跨池转账mn_shield... - 调用Midnight方法前,务必使用进行校验
isMidnightWallet(wallet)
与其他技能的关联:
- 不使用Dynamic的原生DApp连接器 →
react-wallet-connector/ - 通过1AM直接部署合约+调用电路 →
1am-wallet/ - 仅使用嵌入式钱包 → 参考本技能第17节()
DynamicWaasMidnightConnectors
1) Project Structure
1) 项目结构
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.tsmy-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.ts2) Prerequisites
2) 前置条件
- 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)
- Node.js 18+
- Dynamic.xyz账户,且已在「Chains & Networks」中启用Midnight
- 从控制台获取的Dynamic Environment ID
- 注入式流程:已安装1AM wallet浏览器扩展
- 嵌入式流程:在「Embedded Wallets → Security」中启用Private Key Exports(MPC Midnight钱包必需)
3) Scaffold & Install
3) 搭建与安装
bash
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.2Create :
.envbash
VITE_DYNAMIC_ENVIRONMENT_ID=your-environment-id-herebash
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创建文件:
.envbash
VITE_DYNAMIC_ENVIRONMENT_ID=your-environment-id-here4) package.json
package.json4) package.json
package.jsonjson
{
"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 allpackages to the same version. Check@dynamic-labs/*if install fails.npm view @dynamic-labs/midnight version
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"
}
}所有包需锁定同一版本。若安装失败,可通过@dynamic-labs/*查看最新版本。npm view @dynamic-labs/midnight version
5) vite.config.ts
vite.config.ts5) vite.config.ts
vite.config.tstypescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
});typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
});6) tsconfig.json
/ tsconfig.app.json
/ tsconfig.node.json
tsconfig.jsontsconfig.app.jsontsconfig.node.json6) tsconfig.json
/ tsconfig.app.json
/ tsconfig.node.json
tsconfig.jsontsconfig.app.jsontsconfig.node.jsonUse the standard Vite template configs (same as §6–8).
react-tsreact-wallet-connector/SKILL.md使用标准Vite 模板配置(与第6–8节一致)。
react-tsreact-wallet-connector/SKILL.md7) src/vite-env.d.ts
src/vite-env.d.ts7) src/vite-env.d.ts
src/vite-env.d.tstypescript
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_DYNAMIC_ENVIRONMENT_ID: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}typescript
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_DYNAMIC_ENVIRONMENT_ID: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}8) src/main.tsx
src/main.tsx8) src/main.tsx
src/main.tsxtsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);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
src/App.tsx9) src/App.tsx
src/App.tsxInjected 1AM extension flow (default template):
tsx
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>
);
}注入式1AM扩展流程(默认模板):
tsx
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
src/hooks/useMidnightWallet.ts10) src/hooks/useMidnightWallet.ts
src/hooks/useMidnightWallet.tstypescript
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,
};
}typescript
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
src/MidnightWalletPanel.tsx11) src/MidnightWalletPanel.tsx
src/MidnightWalletPanel.tsxDisplays all three surfaces and balances. No CSS — add Tailwind or your preferred styling.
tsx
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>
);
}展示所有三种交互层面及余额。未包含CSS——可自行添加Tailwind或其他样式方案。
tsx
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>通过上方组件连接你的Midnight钱包。</p>;
}
return (
<div>
<h2>钱包交互层面</h2>
<dl>
<dt>未屏蔽(公开)</dt>
<dd title={unshieldedAddress}>{unshieldedAddress}</dd>
<dt>已屏蔽(私有)</dt>
<dd title={shieldedAddress ?? ''}>{shieldedAddress ?? '—'}</dd>
<dt>DUST(手续费)</dt>
<dd title={dustAddress ?? ''}>{dustAddress ?? '—'}</dd>
</dl>
<h2>余额</h2>
{loading ? <p>加载中…</p> : null}
{error ? <p role="alert">{error}</p> : null}
{balances ? (
<ul>
<li>未屏蔽NIGHT: {balances.unshieldedBalance ?? '0'}</li>
<li>已屏蔽NIGHT: {balances.shieldedBalance ?? '0'}</li>
<li>
DUST:{' '}
{balances.dustBalance
? `${balances.dustBalance.balance} / 上限 ${balances.dustBalance.cap}`
: '—'}
</li>
</ul>
) : null}
<button type="button" onClick={() => void refreshBalances()}>
刷新余额
</button>
<h2>存款说明</h2>
<p>
发送至<strong>未屏蔽</strong>地址以存入公开NIGHT,发送至<strong>已屏蔽</strong>地址以存入私有NIGHT。DUST由已注册的未屏蔽NIGHT生成——无需直接向其存款。
</p>
</div>
);
}12) index.html
index.html12) index.html
index.htmlhtml
<!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>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
.env.example13) .env.example
.env.examplebash
VITE_DYNAMIC_ENVIRONMENT_ID=bash
VITE_DYNAMIC_ENVIRONMENT_ID=14) Run
14) 运行
bash
cp .env.example .envbash
cp .env.example .envPaste your Dynamic Environment ID
粘贴你的Dynamic Environment ID
npm install
npm run dev
Open `http://localhost:5173`. Click **DynamicWidget** → connect 1AM wallet → panel shows three surfaces and balances.
---npm install
npm run dev
打开`http://localhost:5173`。点击**DynamicWidget** → 连接1AM钱包 → 面板将展示三种交互层面及余额。
---15) Checking Wallet Type
15) 校验钱包类型
tsx
import { isMidnightWallet } from '@dynamic-labs/midnight';
if (!isMidnightWallet(wallet)) {
throw new Error('This wallet is not a Midnight wallet');
}Always narrow before calling , , or connector methods.
getFormattedBalances()sendBalance()tsx
import { isMidnightWallet } from '@dynamic-labs/midnight';
if (!isMidnightWallet(wallet)) {
throw new Error('该钱包并非Midnight钱包');
}调用、或连接器方法前,务必先进行类型校验。
getFormattedBalances()sendBalance()16) Richer Shielded Handles (Connector API)
16) 增强已屏蔽地址处理(连接器API)
When circuits need coin/encryption public keys:
tsx
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 provider sessions on top of Dynamic.
1am-wallet/当电路需要代币/加密公钥时:
tsx
const connector = primaryWallet.connector;
const { shieldedAddress, shieldedCoinPublicKey, shieldedEncryptionPublicKey } =
await connector.getShieldedAddresses();
const { unshieldedAddress } = await connector.getUnshieldedAddress();
const { dustAddress } = await connector.getDustAddress();在Dynamic之上集成提供方会话时可使用这些方法。
1am-wallet/17) Embedded Wallets (Social / Email)
17) 嵌入式钱包(社交/邮箱)
Swap connector in :
App.tsxtsx
import { DynamicWaasMidnightConnectors } from '@dynamic-labs/midnight';
<DynamicContextProvider
settings={{
environmentId,
walletConnectors: [DynamicWaasMidnightConnectors],
}}
>Dashboard requirements:
- Enable Midnight under Chains & Networks
- Enable Private Key Exports under Embedded Wallets → Security (403 on all ops if disabled)
Embedded balance shape differs slightly:
tsx
const { unshieldedBalance, shieldedTokenCount, dustBalance, dustSyncing } =
await primaryWallet.getFormattedBalances();
// Poll until DUST sync completes (WaaS only)
if (dustSyncing) {
setTimeout(() => void refreshBalances(), 2500);
}Embedded-only extras: , , step-by-step → → .
registerDust()signMessage()createTransferTransactionsignTransactionsubmitTransaction在中替换连接器:
App.tsxtsx
import { DynamicWaasMidnightConnectors } from '@dynamic-labs/midnight';
<DynamicContextProvider
settings={{
environmentId,
walletConnectors: [DynamicWaasMidnightConnectors],
}}
>控制台要求:
- 在「Chains & Networks」中启用Midnight
- 在「Embedded Wallets → Security」中启用Private Key Exports(若禁用,所有操作将返回403错误)
嵌入式钱包的余额结构略有不同:
tsx
const { unshieldedBalance, shieldedTokenCount, dustBalance, dustSyncing } =
await primaryWallet.getFormattedBalances();
// 轮询直至DUST同步完成(仅WaaS)
if (dustSyncing) {
setTimeout(() => void refreshBalances(), 2500);
}嵌入式钱包专属功能:、、分步式 → → 。
registerDust()signMessage()createTransferTransactionsignTransactionsubmitTransaction18) Sending Tokens
18) 发送代币
tsx
// 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:
tsx
const { shielded, unshielded, dust } = await primaryWallet.getBalances();tsx
// 根据接收方前缀路由——mn_shield... = 已屏蔽池,其他为未屏蔽池
await primaryWallet.sendBalance({
toAddress: 'mn_shield...',
amount: '1.5', // 扩展钱包使用人类可读格式的NIGHT
});不支持跨池转账。发送方与接收方必须处于同一资金池。
如需获取原始代币余额:
tsx
const { shielded, unshielded, dust } = await primaryWallet.getBalances();19) Ownership Boundaries
19) 职责边界
| Layer | Owns |
|---|---|
| Dynamic | Connection lifecycle, connectors, |
| 1AM extension | Key custody, derivation, ZK proving, signing, submission |
| Your DApp | Deposit/receive UX (show unshielded and shielded), which pool to display, DUST generation messaging |
| 层级 | 负责内容 |
|---|---|
| Dynamic | 连接生命周期、连接器、 |
| 1AM扩展 | 密钥托管、派生、零知识证明、签名、交易提交 |
| 你的DApp | 存款/收款用户体验(展示未屏蔽和已屏蔽地址)、显示哪个资金池、DUST生成相关提示 |
20) Troubleshooting
20) 故障排查
| Symptom | Cause | Fix |
|---|---|---|
| Midnight not in widget | Chain disabled | Enable Midnight in Dynamic dashboard → Chains & Networks |
| 403 on all wallet methods (embedded) | Private Key Exports off | Enable under Embedded Wallets → Security |
| Wrong connector or chain | Use |
| Shielded address missing | Wallet still syncing | Retry after connect; poll |
| Send fails cross-pool | | Same pool only — unshielded to unshielded, shielded to shielded |
| Version mismatch errors | Mixed | Pin all Dynamic packages to same version |
| Empty DUST | NIGHT not registered | Call |
| 症状 | 原因 | 解决方法 |
|---|---|---|
| 组件中未显示Midnight | 链未启用 | 在Dynamic控制台「Chains & Networks」中启用Midnight |
| 所有钱包方法返回403(嵌入式) | 未开启私钥导出 | 在「Embedded Wallets → Security」中启用该功能 |
| 连接器或链错误 | 使用 |
| 已屏蔽地址缺失 | 钱包仍在同步 | 连接后重试;WaaS需轮询 |
| 跨池转账失败 | | 仅支持同池转账——未屏蔽转未屏蔽,已屏蔽转已屏蔽 |
| 版本不匹配错误 | | 所有Dynamic包锁定同一版本 |
| DUST余额为空 | NIGHT未注册 | 存入未屏蔽NIGHT后调用 |
21) Agent Checklist
21) Agent检查清单
When generating this template for a user:
- Scaffold Vite or write all files from this skill
react-ts - Install ,
@dynamic-labs/sdk-react-core,@dynamic-labs/midnightat same version@dynamic-labs/sdk-api-core - Set in
VITE_DYNAMIC_ENVIRONMENT_ID.env - Use for extension (default) or
MidnightWalletConnectorsfor embeddedDynamicWaasMidnightConnectors - Include for connect/disconnect
DynamicWidget - Surface unshielded, shielded, and DUST in deposit UI
- Guard all Midnight calls with
isMidnightWallet - Omit CSS unless user requests styling
- Link to if user needs contract deploy on top of Dynamic connection
1am-wallet/
为用户生成此模板时需确保:
- 搭建Vite 项目或根据本技能编写所有文件
react-ts - 安装同一版本的、
@dynamic-labs/sdk-react-core、@dynamic-labs/midnight@dynamic-labs/sdk-api-core - 在中设置
.envVITE_DYNAMIC_ENVIRONMENT_ID - 扩展钱包使用(默认),嵌入式钱包使用
MidnightWalletConnectorsDynamicWaasMidnightConnectors - 包含用于连接/断开钱包
DynamicWidget - 在存款UI中展示未屏蔽、已屏蔽和DUST地址
- 所有Midnight调用前使用校验
isMidnightWallet - 除非用户要求,否则不包含CSS
- 若用户需要在Dynamic连接之上部署合约,链接至技能
1am-wallet/
22) Related Skills
22) 相关技能
| Need | Skill |
|---|---|
| DApp Connector without Dynamic | |
| Contract deploy + circuits | |
| Token units & pools | |
| Locker / payment vault dApps | |
| 需求 | 技能 |
|---|---|
| 不使用Dynamic的DApp连接器 | |
| 合约部署+电路调用 | |
| 代币单位与资金池 | |
| 锁仓/支付金库DApp | |