@ducat-unit/wallet-snap

中文文档
0.3.2发布于 2026/11/06MITCommonJS近 30 天下载 1.4万

Ducat Bitcoin account and signing Snap for MetaMask.

原始使用文档
文档目录7 节
  1. What are snaps?
  2. RPC methods
  3. Network Profiles and Endpoint Overrides
  4. Development
  5. Home and confirmation screens
  6. Security
  7. License

Ducat Snap

A MetaMask snap for Bitcoin accounts and signing in the Ducat protocol.

It derives Bitcoin accounts from the user's MetaMask Secret Recovery Phrase, keeps the keys inside MetaMask, and exposes a small JSON-RPC API to the Ducat web app for message signing, complete wallet inventory and PSBT signing. The web app drives everything the user does — borrow, repay, withdraw, and so on — and the snap handles account discovery and the MetaMask confirmation prompts.

The production artifact supports exactly mainnet and mutinynet. The role-neutral local development artifact adds regtest. The Snap has no separate alpha-mainnet wallet network. Its Mainnet and Mutinynet profiles use the same production Mutinynet validator URL while retaining their existing Bitcoin address, transaction, genesis, and wallet-derivation rules.

What are snaps?

Snaps let developers extend MetaMask with capabilities it doesn't ship by default — like support for non-EVM chains. They run in an isolated environment with a limited set of permissions. See the MetaMask Snaps docs for more.

RPC methods

ducat_getAccounts({ network })
ducat_getCapabilities()
ducat_getNetwork()
ducat_getWalletInventory({ network })
ducat_signMessage({ network, address, message })
ducat_signPsbt({ network, psbt, signInputs, context })
ducat_signBatch({ network, entries, context })
ducat_switchNetwork({ network })

ducat_getCapabilities() reports derivationScheme: "ducat-snap/v1". The Snap requests the three final managed role nodes directly: sats at m/84'/<coin>'/0'/0/0, UNIT at m/86'/<coin>'/0'/0/0, and vault at m/86'/<coin>'/0'/2/0, where <coin> is 0 on Mainnet and 1 on Mutinynet and Regtest. Ducat reserves role branch 2 for the vault client key; standard branch 1 remains available for Bitcoin change addresses. Reinstalling MetaMask from the same Secret Recovery Phrase recovers the same managed accounts for this scheme. An imported key selected in Snap Home is an explicit override and is not derived from this scheme.

The beta integration preserves all published 0.3.1 managed paths, including the vault's /2/0 suffix. It does not switch existing users to the older beta /0/1 vault key or migrate their vaults. Release verification checks the built Snap against the 0.3.1 account fixtures, including fresh recovery, on Mainnet, Mutinynet, and Regtest.

The Snap owns one explicit deployment selection. New production installations default to mutinynet. ducat_getNetwork() returns that selection; ducat_switchNetwork() changes it only after a MetaMask-owned confirmation showing the requesting origin, the From and To networks, the effective validator and Esplora origins, and the signing-context warning. A same-network switch is a confirmation-free no-op.

Every deployment-sensitive method must exactly match the selected deployment. A mismatch fails before account derivation, endpoint access, notifications, signing prompts, or state mutation with NETWORK_MISMATCH details containing only selectedNetwork and requestedNetwork. features.explicitNetworkSelection advertises this contract. Legacy state with lastNetwork is migrated once to selectedNetwork; recent actions, keys, endpoint overrides, and origin metadata for supported networks are preserved. State belonging to removed alpha-mainnet, Signet, or Testnet4 Snap networks is discarded rather than renamed or migrated into Mainnet.

The production artifact allows exactly these Ducat app origins:

https://app.ducatprotocol.com
https://dev.ducatprotocol.com
https://test.ducatprotocol.com

localhost and preview deployments are intentionally absent from the published manifest. The development artifact replaces this list with exactly http://localhost:3000, http://localhost:8075, http://frontend:3000, http://ducat-admin:8075, and https://dev.ducatprotocol.com; it does not inherit other production origins. It contains exactly regtest, mainnet, and mutinynet, defaults to mutinynet, and disables debug and unprompted signing. The test-only unprompted method refuses every deployment mapped to Bitcoin mainnet before wallet state, endpoints, entropy, prompts, or signing are touched. Ordinary signing remains prompted for every admitted deployment.

Infra builds the ignored development candidate under .snap/dev, gates it while no server is running, and serves those frozen bytes only at local:http://localhost:8086. Frontend and Admin are caller workflows of this one local Snap; neither is an artifact-policy class. Production packaging stays on the isolated production policy and contains no localhost or removed wallet network authority. Both production and development artifacts use the same shared validator URL for Mainnet and Mutinynet; Regtest stays local.

From ducat-infra, use make snap-down, make snap-install, and make snap-check before make snap-serve. Starting Admin does not build, start, stop, or log the shared Snap. Snap install/update, key import, funding, prompting, signing, and broadcast each remain separate operator approvals. The bundled Mainnet profile requires the production contract identity; an Alpha-configured validator is not compatible with it.

Network Profiles and Endpoint Overrides

The Snap ships bundled network profiles in src/network-profiles.json. Each profile carries a canonical Snap network, the Bitcoin network used for address, transaction, transport, and genesis mechanics, and the exact chain_network value expected from its validator:

Snap networkValidator URLRequired chain_network
Mainnethttps://validator-mainnet.prod.ducatprotocol.commain
Mutinynethttps://validator-mutinynet.prod.ducatprotocol.commutiny

main is Ducat Core's production chain identity; mainnet remains the Snap's wallet network name. The endpoint update does not change any 0.3.1 account derivation paths. A failed production request does not fall back to a dev or alpha validator.

Each validator must report its own network identity. Mainnet rejects Mutinynet data, and neither profile falls back to the other network when unavailable.

Users can set validator and Esplora endpoint overrides from Snap Home. Overrides are stored in Snap state and apply to complete wallet inventory and signing verification. Existing explicit overrides remain selected; clear them in Settings to use the bundled production defaults. Dapps pass only the target network name; they do not pass arbitrary endpoint URLs into signing or inventory RPC calls. Remote overrides require HTTPS and are verified against the selected Bitcoin network before they are stored. An override changes only the URL; it cannot change the profile's expected validator identity. Plain HTTP is limited to regtest loopback development.

Snap Home uses the same confirmed switch flow as website requests. Endpoint and key forms re-read the selected network before changing network-scoped state, so a stale Home screen cannot modify a different network.

Development

For the local Flask connector, run npm run preview:flask and open http://localhost:3000 in the browser with MetaMask Flask installed. The connector installs or updates local:http://localhost:8086. After source changes, stop the preview server and run the command again, then reconnect to load the rebuilt Snap. The server holds a verified snapshot of the bundle and manifest, so it never serves mismatched files during a rebuild.

npm ci
npm run build        # mm-snap build -> dist/bundle.js
npm run manifest     # regenerate the manifest shasum
npm run serve        # serve the snap at http://localhost:8080

The ducat-infra local stack uses make snap-check to generate and validate .snap/dev, then make snap-serve to serve the unchanged candidate. Localhost origins and the development bundle shasum are written only to that ignored runtime; the tracked manifest remains the production HTTPS policy. Development preparation rejects missing, duplicate, credential-bearing, path-bearing, query-bearing, fragment-bearing, and malformed origin entries instead of extending the production list.

Before opening a PR:

npm run type-check
npm test
npm run verify:harness   # MetaMask simulation harness (accounts, signing, BitVM3)

Point the frontend at the local build with NEXT_PUBLIC_DUCAT_SNAP_ID="local:http://localhost:8080", or at the published package with NEXT_PUBLIC_DUCAT_SNAP_ID="npm:@ducat-unit/wallet-snap".

Home and confirmation screens

Snap Home displays BTC, UNIT, and the permitted MetaMask ETH account, with Bitcoin, UNIT, ETH, wUNIT, and USDC balances. The Ethereum provider permission is used for account discovery only; opening Home can request missing account access, while navigation reads existing access without prompting again. Ethereum balances use Ethereum mainnet or Sepolia according to the selected Snap network. wUNIT is configured for Sepolia; its mainnet address remains unset until deployment. Price quotes and EVM balances are display-only and are not used to authorize Bitcoin signing.

Settings contains the network selector, Bitcoin key override, and endpoint editors. Copy fields and editing controls use native Snap components. Vault confirmations show the action amount, destination, and verified before/after values. Transaction sections start collapsed; full addresses remain in Addresses & signing details. Raw UNIT inventory and app metadata sections are omitted from confirmations. Input ownership, previous-output, network, fee, and signing checks still run independently of these displays. Vault comparison metadata remains internal to the Snap; the public wallet inventory RPC retains its existing response shape for compatible apps.

Security

Keys, child keys, WIFs, and raw entropy never leave the snap. The manifest grants entropy access only at the six complete ducat-snap/v1 role paths. Only derived Ducat accounts are signed for (with a Snap Home imported-key override taking precedence when present), only the explicit signInputs indexes are signed, and every signing path requires a MetaMask confirmation in the production artifact. Frontend-supplied context is treated as untrusted display metadata — the parsed PSBT plus fresh Snap-owned wallet/prevout evidence is the source of truth for what's actually signed. Websites construct and broadcast transactions. Taproot vault inputs must carry a Ducat cosign tapleaf whose control block recomputes to the prevout output key.

The third-party security audit (Sayfer) is in docs/audit.pdf.

License

See LICENSE.

版本与发布记录

@ducat-unit/wallet-snap 共发布 13 个版本,首次发布于 2026/06/14;过去 12 个月发布了 13 个版本。

版本发布日期距今
0.3.2latest2026/11/067 天前
0.3.12026/09/012 个月前
0.3.02026/08/292 个月前
0.2.32026/06/264 个月前
0.2.22026/06/264 个月前
0.2.12026/06/264 个月前

关于 @ducat-unit/wallet-snap 的常见问题

@ducat-unit/wallet-snap 是什么?

Ducat Bitcoin account and signing Snap for MetaMask.

如何安装 @ducat-unit/wallet-snap?

在项目目录运行 npm install @ducat-unit/wallet-snap,或使用 pnpm add / yarn add / bun add。

@ducat-unit/wallet-snap 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/ducat-unit__wallet-snap 是否存在。

@ducat-unit/wallet-snap 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@ducat-unit/wallet-snap 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ducat-unit/wallet-snap 可以商用吗?

@ducat-unit/wallet-snap 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ducat-unit/wallet-snap 的下载量有多少?

根据 npm 官方下载统计,@ducat-unit/wallet-snap 在 2026/10/13 – 2026/11/11 这 30 天内被下载 13,552 次,日均约 452 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ducat-unit/wallet-snap 还在维护吗?

最新版本 0.3.2 发布于 2026/11/06(7 天前);至今共发布 13 个版本,其中过去 12 个月发布了 13 个;首次发布于 2026/06/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。