@ducat-unit/wallet-snap 0.1.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -137
- package/dist/bundle.js +1 -1
- package/package.json +3 -17
- package/snap.manifest.json +2 -2
- package/AUDIT_SCOPE.md +0 -46
- package/DEMO_SCRIPT.md +0 -35
- package/DEPENDENCY_AUDIT.md +0 -36
- package/LISTING.md +0 -44
- package/PRIVACY.md +0 -13
- package/RELEASE_CHECKLIST.md +0 -55
- package/SECURITY.md +0 -12
- package/SNAPPER_REVIEW.md +0 -36
- package/SUPPORT.md +0 -9
package/README.md
CHANGED
|
@@ -1,165 +1,78 @@
|
|
|
1
|
-
# Ducat
|
|
1
|
+
# Ducat Snap
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A MetaMask snap for Bitcoin accounts and signing in the [Ducat](https://ducatprotocol.com) protocol.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It derives Bitcoin accounts from the user's MetaMask Secret Recovery Phrase, keeps the keys
|
|
6
|
+
inside MetaMask, and exposes a small JSON-RPC API to the Ducat web app for message signing,
|
|
7
|
+
PSBT signing, and simple transfers. The web app drives everything the user does — borrow,
|
|
8
|
+
repay, withdraw, and so on — and the snap handles account discovery and the MetaMask
|
|
9
|
+
confirmation prompts.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
> Mainnet, signet, and mutinynet are supported. Local development against regtest needs a
|
|
12
|
+
> dev build (see below).
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
- Snap ID: `npm:@ducat-unit/wallet-snap`
|
|
11
|
-
- Proposed Snap name: `Ducat`
|
|
12
|
-
- Audit candidate tag: `audit-candidate-0.1.9-20260617-release-0.1.9`
|
|
13
|
-
- Audit candidate commit: tag target for `audit-candidate-0.1.9-20260617-release-0.1.9`
|
|
14
|
-
- GitHub verification: `Verify Ducat Snap`
|
|
15
|
-
- Manifest source shasum: `u1SC4s8yatFtFEE1IbLPvx2irYCtR/WOm0PtAx81qUs=`
|
|
16
|
-
- Package candidate digest evidence: `RELEASE_EVIDENCE.md`
|
|
14
|
+
## What are snaps?
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
Snaps let developers extend MetaMask with capabilities it doesn't ship by default — like
|
|
17
|
+
support for non-EVM chains. They run in an isolated environment with a limited set of
|
|
18
|
+
permissions. See the [MetaMask Snaps docs](https://docs.metamask.io/snaps/) for more.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
- Mainnet: enabled in this audit candidate
|
|
22
|
-
- Derivation paths:
|
|
23
|
-
- sats mainnet: `m/84'/0'/0'/0/0`, P2WPKH `bc1q...`, compressed 33-byte public key
|
|
24
|
-
- runes mainnet: `m/86'/0'/0'/0/0`, P2TR `bc1p...`, x-only 32-byte internal public key
|
|
25
|
-
- vault mainnet: `m/86'/0'/0'/0/1`, P2TR `bc1p...`, x-only 32-byte internal public key
|
|
26
|
-
- sats testnet: `m/84'/1'/0'/0/0`, P2WPKH `tb1q...`, compressed 33-byte public key
|
|
27
|
-
- runes testnet: `m/86'/1'/0'/0/0`, P2TR `tb1p...`, x-only 32-byte internal public key
|
|
28
|
-
- vault testnet: `m/86'/1'/0'/0/1`, P2TR `tb1p...`, x-only 32-byte internal public key
|
|
20
|
+
## RPC methods
|
|
29
21
|
|
|
30
|
-
## Install
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm ci
|
|
34
22
|
```
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
npm run harness:accounts
|
|
44
|
-
npm run harness:smoke-signing
|
|
23
|
+
ducat_getAccounts({ network })
|
|
24
|
+
ducat_getCapabilities()
|
|
25
|
+
ducat_getHomeState({ network })
|
|
26
|
+
ducat_signMessage({ network, address, message })
|
|
27
|
+
ducat_signPsbt({ network, psbt, signInputs, context })
|
|
28
|
+
ducat_signBatch({ network, entries, context })
|
|
29
|
+
ducat_sendTransfer({ network, address, amountSats, feeRate })
|
|
30
|
+
ducat_clearRecentActions()
|
|
45
31
|
```
|
|
46
32
|
|
|
47
|
-
|
|
33
|
+
Only the Ducat app origins below are allowed to call these:
|
|
48
34
|
|
|
49
|
-
```bash
|
|
50
|
-
npm run verify:release
|
|
51
35
|
```
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
## Run Locally
|
|
56
|
-
|
|
57
|
-
Serve the local Snap:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
npm run serve
|
|
36
|
+
https://app.ducatprotocol.com
|
|
37
|
+
https://dev.app.ducatprotocol.com
|
|
38
|
+
https://staging.app.ducatprotocol.com
|
|
61
39
|
```
|
|
62
40
|
|
|
63
|
-
|
|
41
|
+
`localhost` and preview deployments are intentionally not in the published manifest — a local
|
|
42
|
+
process or a hijacked preview subdomain should never be able to drive mainnet signing. For
|
|
43
|
+
local QA, build with the dev origins/regtest flags (`DUCAT_SNAP_DEV_ORIGINS`,
|
|
44
|
+
`DUCAT_SNAP_DEV_REGTEST`); those are stripped from the published build.
|
|
64
45
|
|
|
65
|
-
|
|
66
|
-
http://localhost:8080
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
For local frontend testing:
|
|
46
|
+
## Development
|
|
70
47
|
|
|
71
48
|
```bash
|
|
72
|
-
|
|
73
|
-
|
|
49
|
+
npm ci
|
|
50
|
+
npm run build # mm-snap build -> dist/bundle.js
|
|
51
|
+
npm run manifest # regenerate the manifest shasum
|
|
52
|
+
npm run serve # serve the snap at http://localhost:8080
|
|
74
53
|
```
|
|
75
54
|
|
|
76
|
-
|
|
55
|
+
Before opening a PR:
|
|
77
56
|
|
|
78
57
|
```bash
|
|
79
|
-
|
|
80
|
-
|
|
58
|
+
npm run type-check
|
|
59
|
+
npm test
|
|
60
|
+
npm run verify:harness # MetaMask simulation harness (accounts, signing, BitVM3)
|
|
81
61
|
```
|
|
82
62
|
|
|
83
|
-
|
|
63
|
+
Point the frontend at the local build with `NEXT_PUBLIC_DUCAT_SNAP_ID="local:http://localhost:8080"`,
|
|
64
|
+
or at the published package with `NEXT_PUBLIC_DUCAT_SNAP_ID="npm:@ducat-unit/wallet-snap"`.
|
|
84
65
|
|
|
85
|
-
|
|
86
|
-
- `https://dev.app.ducatprotocol.com`
|
|
87
|
-
- `https://staging.app.ducatprotocol.com`
|
|
66
|
+
## Security
|
|
88
67
|
|
|
89
|
-
|
|
68
|
+
Keys, child keys, WIFs, and raw entropy never leave the snap. Only derived Ducat accounts are
|
|
69
|
+
signed for, only the explicit `signInputs` indexes are signed, and every signing path requires a
|
|
70
|
+
MetaMask confirmation. Frontend-supplied context is treated as untrusted display metadata — the
|
|
71
|
+
parsed PSBT is the source of truth for what's actually signed. Taproot vault inputs must carry a
|
|
72
|
+
Ducat cosign tapleaf whose control block recomputes to the prevout output key.
|
|
90
73
|
|
|
91
|
-
|
|
74
|
+
The third-party security audit (Sayfer) is in [`docs/audit.pdf`](docs/audit.pdf).
|
|
92
75
|
|
|
93
|
-
|
|
94
|
-
- `ducat_getCapabilities()`
|
|
95
|
-
- `ducat_signMessage({ network, address, message })`
|
|
96
|
-
- `ducat_signPsbt({ network, psbt, signInputs, context })`
|
|
97
|
-
- `ducat_signBatch({ network, entries, context })`
|
|
98
|
-
- `ducat_sendTransfer({ network, address, amountSats, feeRate })`
|
|
99
|
-
- `ducat_getHomeState({ network })`
|
|
100
|
-
- `ducat_clearRecentActions()`
|
|
76
|
+
## License
|
|
101
77
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
MetaMask confirmations are action-specific and structured:
|
|
105
|
-
|
|
106
|
-
- Message signing shows the Ducat action label, origin, network, account, BIP322 signature type, message length, message fingerprint, and copyable message body.
|
|
107
|
-
- PSBT signing shows the Ducat action label, origin, network, summary rows, signed input details, output details, fee, warnings, and Ducat app metadata.
|
|
108
|
-
- Batch signing shows transaction count, all-or-nothing semantics, total fee, per-transaction summaries, and warning count.
|
|
109
|
-
- Simple BTC transfer shows amount, estimated fee, `You pay`, change, sender, recipient, selected UTXOs, and broadcast endpoint.
|
|
110
|
-
- Snap Home shows last connected network, copyable BTC/UNIT/vault addresses, public balance and vault lookups when available, recent action state, approved HTTPS Ducat app links, and local development routes.
|
|
111
|
-
|
|
112
|
-
Errors returned to the frontend include a stable `code`, user-facing `message`, and diagnostic `details` for expanded debugging.
|
|
113
|
-
|
|
114
|
-
## Security Model
|
|
115
|
-
|
|
116
|
-
- Private keys, child private keys, WIFs, and raw entropy never leave the Snap.
|
|
117
|
-
- The Snap requests Bitcoin mainnet and testnet BIP32 entropy paths: `m/84'/0'`, `m/86'/0'`, `m/84'/1'`, and `m/86'/1'`.
|
|
118
|
-
- Mainnet requests use Bitcoin mainnet addresses, transaction parsing, and broadcast endpoints; signet and mutinynet requests use Bitcoin testnet parameters.
|
|
119
|
-
- Unauthorized origins cannot invoke the Snap RPC API.
|
|
120
|
-
- Only explicit `signInputs` indexes are signed.
|
|
121
|
-
- Signing is restricted to derived Ducat Snap accounts.
|
|
122
|
-
- Message, PSBT, batch, and transfer signing require MetaMask confirmation.
|
|
123
|
-
- Frontend context is treated as untrusted display metadata. Parsed PSBT data is the signing source of truth.
|
|
124
|
-
- Snap state stores recent Ducat action metadata only.
|
|
125
|
-
|
|
126
|
-
Taproot script-path inputs must include a Ducat cosign tapleaf and control-block data that recomputes to the prevout P2TR output key. The tapleaf must place the derived Ducat vault key in the client slot, and the client and guard pubkeys must be distinct. The Snap rejects uncommitted script-path inputs, client/guard key collapse, and generic leaves even when a leaf contains the derived vault key.
|
|
127
|
-
|
|
128
|
-
## Audit And Submission Packet
|
|
129
|
-
|
|
130
|
-
Primary audit documents:
|
|
131
|
-
|
|
132
|
-
- `AUDITOR_HANDOFF.md`
|
|
133
|
-
- `AUDIT_SCOPE.md`
|
|
134
|
-
- `RELEASE_EVIDENCE.md`
|
|
135
|
-
- `INTERNAL_SECURITY_REVIEW.md`
|
|
136
|
-
- `DEPENDENCY_AUDIT.md`
|
|
137
|
-
- `SNAPPER_REVIEW.md`
|
|
138
|
-
|
|
139
|
-
Submission documents:
|
|
140
|
-
|
|
141
|
-
- `submission/README.md`
|
|
142
|
-
- `submission/ALLOWLIST_SUBMISSION.md`
|
|
143
|
-
- `submission/EXTERNAL_GATES.md`
|
|
144
|
-
- `submission/metamask-directory.json`
|
|
145
|
-
- `submission/fixtures/README.md`
|
|
146
|
-
- `submission/e2e/README.md`
|
|
147
|
-
- `submission/screenshots/README.md`
|
|
148
|
-
|
|
149
|
-
The source, package, metadata, and local verification evidence are ready for external audit handoff. MetaMask directory submission still requires the third-party audit report, final screenshots, demo video, real transaction fixtures, final E2E evidence, and project-owned support/escalation details listed in `submission/EXTERNAL_GATES.md`.
|
|
150
|
-
|
|
151
|
-
## Useful Commands
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
npm run type-check
|
|
155
|
-
npm test -- --runInBand
|
|
156
|
-
npm run build
|
|
157
|
-
npm run manifest
|
|
158
|
-
npm run verify:harness
|
|
159
|
-
npm run verify:release
|
|
160
|
-
npm run verify:metadata
|
|
161
|
-
npm run verify:release-manifest
|
|
162
|
-
npm run verify:submission-ready
|
|
163
|
-
npm run audit:prod
|
|
164
|
-
npm run pack:dry-run
|
|
165
|
-
```
|
|
78
|
+
See [LICENSE](LICENSE).
|