@ducat-unit/wallet-snap 0.2.2 → 0.3.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 +97 -15
- package/dist/bundle.js +1 -1
- package/images/icon.svg +5 -3
- package/package.json +12 -9
- package/snap.manifest.json +14 -6
package/README.md
CHANGED
|
@@ -4,12 +4,15 @@ A MetaMask snap for Bitcoin accounts and signing in the [Ducat](https://ducatpro
|
|
|
4
4
|
|
|
5
5
|
It derives Bitcoin accounts from the user's MetaMask Secret Recovery Phrase, keeps the keys
|
|
6
6
|
inside MetaMask, and exposes a small JSON-RPC API to the Ducat web app for message signing,
|
|
7
|
-
|
|
7
|
+
complete wallet inventory and PSBT signing. The web app drives everything the user does — borrow,
|
|
8
8
|
repay, withdraw, and so on — and the snap handles account discovery and the MetaMask
|
|
9
9
|
confirmation prompts.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
The production artifact supports exactly `mainnet` and `mutinynet`. The
|
|
12
|
+
role-neutral local development artifact adds `regtest`. The Snap has no
|
|
13
|
+
separate `alpha-mainnet` wallet network: its Mainnet profile currently uses the
|
|
14
|
+
reviewed alpha DUCAT contract while retaining canonical Bitcoin mainnet
|
|
15
|
+
address, transaction, and genesis rules.
|
|
13
16
|
|
|
14
17
|
## What are snaps?
|
|
15
18
|
|
|
@@ -22,15 +25,40 @@ permissions. See the [MetaMask Snaps docs](https://docs.metamask.io/snaps/) for
|
|
|
22
25
|
```
|
|
23
26
|
ducat_getAccounts({ network })
|
|
24
27
|
ducat_getCapabilities()
|
|
25
|
-
|
|
28
|
+
ducat_getNetwork()
|
|
29
|
+
ducat_getWalletInventory({ network })
|
|
26
30
|
ducat_signMessage({ network, address, message })
|
|
27
31
|
ducat_signPsbt({ network, psbt, signInputs, context })
|
|
28
32
|
ducat_signBatch({ network, entries, context })
|
|
29
|
-
|
|
30
|
-
ducat_clearRecentActions()
|
|
33
|
+
ducat_switchNetwork({ network })
|
|
31
34
|
```
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
`ducat_getCapabilities()` reports `derivationScheme: "ducat-snap/v1"`.
|
|
37
|
+
The Snap requests the three final managed role nodes directly: sats at
|
|
38
|
+
`m/84'/<coin>'/0'/0/0`, UNIT at `m/86'/<coin>'/0'/0/0`, and vault at
|
|
39
|
+
`m/86'/<coin>'/0'/2/0`, where `<coin>` is `0` on Mainnet and `1` on
|
|
40
|
+
Mutinynet and Regtest. Ducat reserves role branch `2` for the vault client key;
|
|
41
|
+
standard branch `1` remains available for Bitcoin change addresses. Reinstalling
|
|
42
|
+
MetaMask from the same Secret Recovery Phrase recovers the same managed accounts
|
|
43
|
+
for this scheme. An imported key selected in Snap Home is an explicit override
|
|
44
|
+
and is not derived from this scheme.
|
|
45
|
+
|
|
46
|
+
The Snap owns one explicit deployment selection. New production installations default to
|
|
47
|
+
`mutinynet`. `ducat_getNetwork()` returns that selection; `ducat_switchNetwork()`
|
|
48
|
+
changes it only after a MetaMask-owned confirmation showing the requesting origin,
|
|
49
|
+
the From and To networks, the effective validator and Esplora origins, and the
|
|
50
|
+
signing-context warning. A same-network switch is a confirmation-free no-op.
|
|
51
|
+
|
|
52
|
+
Every deployment-sensitive method must exactly match the selected deployment. A mismatch
|
|
53
|
+
fails before account derivation, endpoint access, notifications, signing prompts, or
|
|
54
|
+
state mutation with `NETWORK_MISMATCH` details containing only `selectedNetwork` and
|
|
55
|
+
`requestedNetwork`. `features.explicitNetworkSelection` advertises this contract.
|
|
56
|
+
Legacy state with `lastNetwork` is migrated once to `selectedNetwork`; recent actions,
|
|
57
|
+
keys, endpoint overrides, and origin metadata for supported networks are preserved.
|
|
58
|
+
State belonging to removed `alpha-mainnet`, Signet, or Testnet4 Snap networks is
|
|
59
|
+
discarded rather than renamed or migrated into Mainnet.
|
|
60
|
+
|
|
61
|
+
The production artifact allows exactly these Ducat app origins:
|
|
34
62
|
|
|
35
63
|
```
|
|
36
64
|
https://app.ducatprotocol.com
|
|
@@ -38,10 +66,54 @@ https://dev.app.ducatprotocol.com
|
|
|
38
66
|
https://staging.app.ducatprotocol.com
|
|
39
67
|
```
|
|
40
68
|
|
|
41
|
-
`localhost` and preview deployments are intentionally
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
`
|
|
69
|
+
`localhost` and preview deployments are intentionally absent from the published
|
|
70
|
+
manifest. The development artifact replaces this list with exactly
|
|
71
|
+
`http://localhost:3000`, `http://localhost:8075`, `http://frontend:3000`, and
|
|
72
|
+
`http://ducat-admin:8075`; it does not inherit production origins. It contains
|
|
73
|
+
exactly `regtest`, `mainnet`, and `mutinynet`, defaults to `mutinynet`, and
|
|
74
|
+
disables debug and unprompted signing.
|
|
75
|
+
The test-only unprompted method refuses every deployment mapped to Bitcoin
|
|
76
|
+
mainnet before wallet state, endpoints, entropy, prompts, or signing are
|
|
77
|
+
touched. Ordinary signing remains prompted for every admitted deployment.
|
|
78
|
+
|
|
79
|
+
Infra builds the ignored development candidate under `.snap/dev`, gates it
|
|
80
|
+
while no server is running, and serves those frozen bytes only at
|
|
81
|
+
`local:http://localhost:8086`. Frontend and Admin are caller workflows of this
|
|
82
|
+
one local Snap; neither is an artifact-policy class. Production packaging stays
|
|
83
|
+
on the isolated production policy and contains no localhost or removed wallet
|
|
84
|
+
network authority. The string `alpha-mainnet` remains only as the Mainnet
|
|
85
|
+
profile's expected validator response while the alpha DUCAT contract is active.
|
|
86
|
+
|
|
87
|
+
From `ducat-infra`, use `make snap-down`, `make snap-install`, and
|
|
88
|
+
`make snap-check` before `make snap-serve`. Starting the Alpha-configured Admin
|
|
89
|
+
does not build, start, stop, or log the shared Snap. Snap install/update, key
|
|
90
|
+
import, funding, prompting, signing, and broadcast each remain separate
|
|
91
|
+
operator approvals. The complete real-Bitcoin sequence and private-key
|
|
92
|
+
handling rules are in
|
|
93
|
+
[`../../dev/runbooks/DUCAT_ADMIN_ALPHA_MAINNET.md`](../../dev/runbooks/DUCAT_ADMIN_ALPHA_MAINNET.md).
|
|
94
|
+
|
|
95
|
+
## Network Profiles and Endpoint Overrides
|
|
96
|
+
|
|
97
|
+
The Snap ships bundled network profiles in [`src/network-profiles.json`](src/network-profiles.json).
|
|
98
|
+
Each profile carries a canonical Snap network, the Bitcoin network used for
|
|
99
|
+
address, transaction, transport, and genesis mechanics, and the exact
|
|
100
|
+
`chain_network` value expected from its validator. The Mainnet profile currently
|
|
101
|
+
expects `alpha-mainnet`; that value is contract-stage evidence, not another Snap
|
|
102
|
+
network. Retiring the alpha contract requires changing the profile expectation
|
|
103
|
+
and validator URL, not adding or migrating a wallet network.
|
|
104
|
+
|
|
105
|
+
Users can set validator and Esplora endpoint overrides from Snap Home. Overrides are
|
|
106
|
+
stored in Snap state and apply to complete wallet inventory and signing verification.
|
|
107
|
+
Dapps pass only
|
|
108
|
+
the target network name; they do not pass arbitrary endpoint URLs into signing or
|
|
109
|
+
inventory RPC calls. Remote overrides require HTTPS and are verified against the
|
|
110
|
+
selected Bitcoin network before they are stored. An override changes only the URL;
|
|
111
|
+
it cannot change the profile's expected validator identity. Plain HTTP is limited
|
|
112
|
+
to regtest loopback development.
|
|
113
|
+
|
|
114
|
+
Snap Home uses the same confirmed switch flow as website requests. Endpoint and key
|
|
115
|
+
forms re-read the selected network before changing network-scoped state, so a stale
|
|
116
|
+
Home screen cannot modify a different network.
|
|
45
117
|
|
|
46
118
|
## Development
|
|
47
119
|
|
|
@@ -52,6 +124,13 @@ npm run manifest # regenerate the manifest shasum
|
|
|
52
124
|
npm run serve # serve the snap at http://localhost:8080
|
|
53
125
|
```
|
|
54
126
|
|
|
127
|
+
The `ducat-infra` local stack uses `make snap-check` to generate and validate
|
|
128
|
+
`.snap/dev`, then `make snap-serve` to serve the unchanged candidate. Localhost
|
|
129
|
+
origins and the development bundle shasum are written only to that ignored
|
|
130
|
+
runtime; the tracked manifest remains the production HTTPS policy. Development preparation rejects missing, duplicate,
|
|
131
|
+
credential-bearing, path-bearing, query-bearing, fragment-bearing, and malformed
|
|
132
|
+
origin entries instead of extending the production list.
|
|
133
|
+
|
|
55
134
|
Before opening a PR:
|
|
56
135
|
|
|
57
136
|
```bash
|
|
@@ -65,10 +144,13 @@ or at the published package with `NEXT_PUBLIC_DUCAT_SNAP_ID="npm:@ducat-unit/wal
|
|
|
65
144
|
|
|
66
145
|
## Security
|
|
67
146
|
|
|
68
|
-
Keys, child keys, WIFs, and raw entropy never leave the snap.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
147
|
+
Keys, child keys, WIFs, and raw entropy never leave the snap. The manifest grants entropy access
|
|
148
|
+
only at the six complete `ducat-snap/v1` role paths. Only derived Ducat accounts are
|
|
149
|
+
signed for (with a Snap Home imported-key override taking precedence when present), only the
|
|
150
|
+
explicit `signInputs` indexes are signed, and every signing path requires a
|
|
151
|
+
MetaMask confirmation in the production artifact. Frontend-supplied context is treated as untrusted display metadata — the
|
|
152
|
+
parsed PSBT plus fresh Snap-owned wallet/prevout evidence is the source of truth for what's actually
|
|
153
|
+
signed. Websites construct and broadcast transactions. Taproot vault inputs must carry a
|
|
72
154
|
Ducat cosign tapleaf whose control block recomputes to the prevout output key.
|
|
73
155
|
|
|
74
156
|
The third-party security audit (Sayfer) is in [`docs/audit.pdf`](docs/audit.pdf).
|