Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
36608ab
Merge branch 'release/1.4.6' into develop
BitHighlander Jun 21, 2026
b32056a
fix(emulator): show Accept/Reject for Enable Policy confirm
BitHighlander Jun 22, 2026
86a7911
fix(auth): stop re-approve churn — idempotent pairing, LRU, sliding T…
BitHighlander Jun 22, 2026
d40e4c0
Merge pull request #283 from keepkey/fix/emulator-enable-policy-confirm
BitHighlander Jun 23, 2026
72d6baf
fix(update): route updates to keepkey.com/update page, no in-app "Dow…
BitHighlander Jun 23, 2026
67a9b1f
fix(watch-only): make Refresh re-fetch balances from cached addresses…
BitHighlander Jun 23, 2026
ae6a935
fix(watch-only): show cached receive address instead of 'No device co…
BitHighlander Jun 23, 2026
ff572cc
fix(emulator): reload saved seed when persisted flash boots a stale/w…
BitHighlander Jun 23, 2026
4d121aa
chore: bump version to 1.4.7
BitHighlander Jun 23, 2026
9b19f61
Merge branch 'release/1.4.7' into develop
BitHighlander Jun 23, 2026
1b6da84
fix(release): force module rebuild in build-signed so stale dist can'…
BitHighlander Jun 25, 2026
3b3f4af
fix(swap): restore localized title, remove hardcoded 'Swaps.pro' bran…
BitHighlander Jun 25, 2026
285ba3e
chore: bump version to 1.4.8
BitHighlander Jun 25, 2026
35891c2
Merge branch 'release/1.4.8' into develop
BitHighlander Jun 25, 2026
7f1e93e
feat(hive): settings feature flag (default off) + fix firmware gate 7…
BitHighlander Jun 26, 2026
54ae5b7
fix(hive): honor feature flag across REST, cached balances, activity …
BitHighlander Jun 26, 2026
1a5dbdc
Merge pull request #293 from keepkey/feat/hive-settings-flag
BitHighlander Jun 26, 2026
a04c5bd
fix(hive): correct derivation path to SLIP-0048 (Phase 0) + onboardin…
BitHighlander Jun 26, 2026
e870557
docs(hive): Pioneer sponsor-service handoff (Phase 2)
BitHighlander Jun 26, 2026
ca14312
docs(hive): resolve §6 attestation — no hardware attest on fw 7.15.0,…
BitHighlander Jun 26, 2026
4b35abc
docs(hive): attestation-digest spec for create-account verification
BitHighlander Jun 26, 2026
f77377d
fix(windows-build): build proto-tx-builder dist (fixes 'createFeegran…
BitHighlander Jun 27, 2026
0ffcb19
THORChain RUJI/TCY/secured-asset custom-denom signing (#292)
BitHighlander Jun 27, 2026
85c0d1c
chore: bump version to 1.4.9
BitHighlander Jun 27, 2026
5973d44
Merge branch 'release/1.4.9' into develop
BitHighlander Jun 27, 2026
9eaa9de
Merge pull request #294 from keepkey/feat/hive-slip48-path
BitHighlander Jun 27, 2026
e9e5235
feat(hive): sponsor-backed account onboarding + ETH anti-drain gate (…
BitHighlander Jun 29, 2026
d2e17b4
feat(recovery): expose cipher-recovery character entry over REST + SD…
BitHighlander Jun 30, 2026
c2e3eaf
chore(sdk-tests): commit untracked device tests for the test suite
BitHighlander Jun 30, 2026
3691b53
fix(dashboard): let new users Receive on a freshly-added zero-balance…
BitHighlander Jun 30, 2026
cb03bf8
test(recovery): match real on-device rejection in wrong-word #272 test
BitHighlander Jun 30, 2026
63d2485
feat(hive): list Hive Support as a v7.15.0 upgrade-preview feature (#…
BitHighlander Jul 1, 2026
34b5c44
docs: firmware-release SOP — upstream-first dependency gating (#304)
BitHighlander Jul 1, 2026
afd4cd9
fix(windows-build): replace em-dashes with ASCII so PowerShell 5.1 ca…
BitHighlander Jul 1, 2026
3156966
docs(zcash): real-device shielded smoke checklist — v1.4.6 stable-pro…
BitHighlander Jul 1, 2026
edc9d31
test(zcash): witness recomputes root for note in lower completed shar…
BitHighlander Jul 1, 2026
f601bde
fix(clear-sign): stop over-gating firmware-handled contracts into bli…
BitHighlander Jul 1, 2026
bb62142
fix(multichain): get addresses for non-BTC chains, not just Bitcoin (…
BitHighlander Jul 1, 2026
aa77c58
fix(wc): use live-camera QR scanner for WalletConnect pairing (#301)
BitHighlander Jul 1, 2026
9ed01ac
fix(zcash): Sync button forces a real device FVK re-verify (#276)
BitHighlander Jul 1, 2026
132a23d
feat(audit): track & recover UTXO-altcoin funds beyond account 0 (#299)
BitHighlander Jul 1, 2026
ce042b3
fix(eth): send empty (not 0x0) for a zero/absent EIP-1559 priority fe…
BitHighlander Jul 1, 2026
b74e39f
fix(hive): gate address derivation on firmware capability (stop USB-d…
BitHighlander Jul 1, 2026
50b63c2
fix(onboarding): reopen setup wizard on needs_init + refactor(dashboa…
BitHighlander Jul 1, 2026
d1a9b51
fix(hive): gate ETH anti-drain gate off until Pioneer implements it (…
BitHighlander Jul 2, 2026
6bf6039
feat(hive): enable ETH anti-drain gate for release (#313)
BitHighlander Jul 2, 2026
2241582
fix(refresh): asset-page refresh actually refreshes (hive derive, sil…
BitHighlander Jul 2, 2026
fd2a6c7
refactor(balances): share the leaf parsing between bulk + single-chai…
BitHighlander Jul 2, 2026
7c3fc5c
fix(hive): thread hiveBuildResult through hiveSignTx RPC response (#317)
BitHighlander Jul 2, 2026
98d6b38
fix(send): delay post-broadcast balance resync (#318)
BitHighlander Jul 2, 2026
5fb6b32
fix(windows): stop corrupting the update/external-link URL via cmd st…
BitHighlander Jul 2, 2026
eb50a18
fix(tron): raise TRC-20 fee_limit 30→100 TRX; display simulated fee, …
BitHighlander Jul 2, 2026
78ebcd4
fix(xrp): stop REST schema from stripping tx + lastLedgerSequence (#309)
BitHighlander Jul 2, 2026
7ef3fbb
feat(audit): LTC uncommon-path pipeline + in-audit sweep to standard …
BitHighlander Jul 2, 2026
002039b
fix(portfolio): sum multi-xpub UTXO chains per pubkey — stop LTC boun…
BitHighlander Jul 2, 2026
59e1441
fix(oob): unstick wizard after custom firmware flash + show signed/un…
BitHighlander Jul 2, 2026
7b0c46d
fix(ui): restore LOW GAS warning for all chain families + swap pre-fl…
BitHighlander Jul 2, 2026
f028a89
feat(qr): third scan option — scan the screen for a QR code (#325)
BitHighlander Jul 2, 2026
b95500f
feat(clearsign): EVM insight behind EVM_INSIGHT flag (default off, fw…
BitHighlander Jul 3, 2026
2df22ca
chore: bump version to 1.4.10
BitHighlander Jul 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,17 @@ prune-bundle:
cd $(PROJECT_DIR) && bun scripts/prune-app-bundle.ts

# Full signed build: electrobun build → audit → prune → extract from tar → create DMG → sign + notarize + staple
# Force-clear zcash-cli stamp so it gets re-signed with Developer ID (stamp may be stale from unsigned build)
# Force-clear stamps so the release always rebuilds from the pinned source:
# - zcash-cli: so it gets re-signed with Developer ID (stamp may be stale from an unsigned build)
# - module build stamps: the proto-tx-builder / hdwallet / device-protocol dist/ output is
# gitignored and copied into the bundle via file: refs. The stamps track src mtimes, but a
# submodule `git checkout` to a new pin does NOT reliably bump src mtimes past an existing
# stamp — so make skips the rebuild and the bundle ships a STALE dist from a previous commit.
# (This shipped the @cosmjs/stargate Freegrant/Feegrant fallback as a pre-fix build in v1.4.6/1.4.7,
# breaking every Cosmos tx with "createFeegrantAminoConverters is not a function".)
# Clearing the stamps forces modules-build from the pinned source before the vault install copies it.
build-signed: sign-check
@rm -f $(ZCASH_CLI_STAMP)
@rm -f $(ZCASH_CLI_STAMP) $(PROTO_BUILD_STAMP) $(HDWALLET_BUILD_STAMP) $(DEVICE_PROTOCOL_BUILD_STAMP)
$(MAKE) build-stable audit prune-bundle dmg
@echo ""
@echo "=== Build complete ==="
Expand Down
182 changes: 182 additions & 0 deletions docs/HIVE-ATTESTATION-DIGEST-SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Hive Account-Creation Attestation Digest Spec

For the Pioneer `create-account` endpoint (§5/§6 of `handoff-pioneer-hive-sponsor.md`).
Derived from firmware 7.15.0 `lib/firmware/hive.c` + `include/keepkey/firmware/hive.h`,
verified 2026-06-26. **Byte-exact** — Pioneer's verification must match this or it silently fails.

---

## 0. TL;DR — not blocked on firmware

In Hive, `account_create` is signed by the **creator (sponsor)**, not the new account (it
doesn't exist yet). So the device's `HiveSignAccountCreate` signature is **not** a broadcast
authority — it is an **attestation**: proof that the owner key holder authorized creating
this account with these four keys, confirmed on-device.

The firmware already produces a well-defined digest and **returns the exact `serialized_tx`
it signed**. Pioneer verifies against those returned bytes — no reconstruction, no firmware
change. The earlier "blocked on firmware attestation-digest spec" status is **cleared**: the
digest below is the spec. A dedicated attestation message would be *nicer* (see §7) but is
not required to ship.

---

## 1. The digest

```
digest = SHA256( chain_id[32] || serialized_tx )
```

- `chain_id` (mainnet, `HIVE_CHAIN_ID`):
`beeab0de` followed by 28 zero bytes (32 bytes total).
- `serialized_tx`: the Graphene `account_create` (op 9) bytes the device built and returned
(§3). Hash the **returned** bytes verbatim; do not rebuild them.

Reference: `hive.c:183-202` (`hive_sign_digest`).

---

## 2. Signature format (65 bytes)

```
sig[0] = 27 + recovery_id + 4 (compact header, compressed-key flag)
sig[1..33] = r (32 bytes)
sig[33..65] = s (32 bytes, canonical low-S from trezor-crypto)
```

To recover the signer:
```
recovery_id = sig[0] - 31 // == 27 + recid + 4 → recid = sig[0]-31
pubkey33 = secp256k1_ecdsa_recover(digest, recovery_id, r, s) // 33-byte compressed
```

Encode `pubkey33` as a Hive public key string: `"STM" + base58check(pubkey33, ripemd160-checksum)`
(Graphene pubkey encoding — 4-byte RIPEMD160 checksum, **not** double-SHA256). Compare against
the supplied `ownerKey`.

> Graphene's extra "is_canonical" retry loop is irrelevant here — Pioneer recovers a pubkey,
> it does not rebroadcast this signature. Reference: `hive.c:194-200`.

---

## 3. `serialized_tx` byte layout (account_create, op 9)

All multi-byte integers little-endian. `varint` = LEB128 unsigned. Reference:
`hive_serialize_account_create` (`hive.c:269-307`), `append_tx_header` (`165-173`),
`append_authority` (`152-161`), `append_asset`/`append_string`/`append_varint` (`hive.c:120-164`).

```
# header
ref_block_num u16 LE # = msg.ref_block_num & 0xFFFF
ref_block_prefix u32 LE
expiration u32 LE
num_ops varint = 0x01
op_type varint = 0x09 (HIVE_OP_ACCOUNT_CREATE)

# account_create body
fee asset: amount u64 LE, precision u8 = 3, symbol[7] = "HIVE\0\0\0"
creator string: varint len || bytes # MUST equal sponsor account name
new_account_name string: varint len || bytes
owner_authority authority(owner_pubkey33)
active_authority authority(active_pubkey33)
posting_authority authority(posting_pubkey33)
memo_key 33 raw bytes # NO authority wrapper, NO type prefix
json_metadata string = "" (varint 0x00)
num_extensions varint = 0x00
```

`authority(pubkey33)`:
```
weight_threshold u32 LE = 1
num_account_auths varint = 0x00
num_key_auths varint = 0x01
pubkey 33 bytes compressed (no type prefix)
weight u16 LE = 1
```

`asset` (fee): `amount(u64 LE) || precision(u8) || symbol(7 bytes, NUL-padded)`.
`string`: `varint(len) || raw bytes`.

> Note: pubkeys inside `serialized_tx` are **raw 33-byte compressed**, not STM strings.
> The STM strings in the request are for the availability/echo path; the authoritative keys
> are these raw bytes — re-encode them to STM to compare against the request (§5 step 5).

---

## 4. account_update (op 10) — same digest, Flow B

Identical digest and signature rules. `serialized_tx` differs only in the body
(`hive_serialize_account_update`, `hive.c:351-388`): `op_type = 0x0A`, then `account`
(string) + the four new authorities/memo_key. Same verification shape; used by the
"secure existing account" flow, not create-account.

---

## 5. Pioneer verification algorithm (create-account)

Input from vault: `{ ownerKey, activeKey, postingKey, memoKey, newAccountName, creator,
refBlockNum, refBlockPrefix, expiration, feeAmount, signature(65B hex), serializedTx(hex) }`.

```
1. tx = hexDecode(serializedTx)
sig = hexDecode(signature) // assert length 65
2. digest = SHA256( HIVE_CHAIN_ID(32) || tx )
3. recid = sig[0] - 31 // assert 0 <= recid <= 3
pub33 = ecdsaRecover(digest, recid, sig[1:33], sig[33:65]) // assert success
recoveredStm = stmEncode(pub33)
4. ASSERT recoveredStm == ownerKey // → 401 if not (proves owner-key control + on-device confirm)
5. Parse tx (§3) and ASSERT, else 400:
- op_type == 9
- new_account_name == newAccountName
- stmEncode(owner_authority.key) == ownerKey
- stmEncode(active_authority.key) == activeKey
- stmEncode(posting_authority.key) == postingKey
- stmEncode(memo_key) == memoKey
- creator == <OUR sponsor account> // binds spend to us; client cannot redirect
6. Run §7 abuse + circuit-breaker gates (handoff). If ACT pool low → 503 queued.
7. Build create_claimed_account (op 23) with { creator: sponsor, new_account_name,
owner/active/posting authorities + memo_key = the four verified keys, json_metadata: "" },
sign with the SPONSOR active key, broadcast. fee_amount from the request is ignored
(claimed-account creation has no fee — it spends one ACT).
```

Step 5 is load-bearing: without it a caller could submit a valid signature over
attacker-chosen bytes. The signature only matters once you've proven the bytes are exactly
what you're about to create.

---

## 6. What the vault must guarantee

- Set `creator = <sponsor account>` **before** calling `hiveSignAccountCreate`, so the
device-signed bytes carry our sponsor (Pioneer rejects any other creator).
- Send Pioneer the device-returned `serializedTx` and `signature` unmodified, plus the four
STM keys + `newAccountName` it used.
- `refBlockNum/Prefix/expiration/feeAmount` are echoed for transparency but Pioneer trusts
only the parsed `serializedTx` for keys/name/creator.

---

## 7. Optional future: dedicated attestation digest (firmware change)

The op-9 digest couples attestation to Graphene serialization, so Pioneer must parse §3.
That parse is ~30 lines of fixed-layout decoding — acceptable. **Ship with this; do not block.**

If Graphene parsing later proves annoying or we want attestation decoupled from tx fields, add
a firmware message that signs a canonical, parse-free digest, e.g.:
```
digest = SHA256( "KK-HIVE-CREATE-v1" || new_account_name
|| owner33 || active33 || posting33 || memo33 )
```
Pioneer would then verify with no Graphene decoding. This is a **new firmware message**
(separate PR), not a change to what 7.15.0 ships — track independently.

---

## 8. Test vector (capture before Pioneer codes verification)

On a real device (fw 7.15.0), call `hiveSignAccountCreate` with fixed inputs and record:
`{ inputs, signature(hex), serializedTx(hex), expected recoveredStm == ownerKey }`. Commit
the vector so Pioneer's verifier has a known-good fixture to test §5 against without a device.
Until this vector exists, treat §2's STM-encoding and recovery-byte handling as
**unverified-by-fixture** (correct by reading firmware, but confirm against device output).
176 changes: 176 additions & 0 deletions docs/HIVE-ONBOARDING-PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Hive Onboarding — Next Steps (Self-Run Sponsor)

Updated: 2026-06-26. Decision: build self-run account creation (Pioneer sponsor).
Supersedes the "What Exists Today" section of `HIVE-FIRMWARE-PLAN.md` — that doc's
v2 spec is still the reference for message shapes; the status below is current truth.

---

## 1. Status truth (verified 2026-06-26)

The expensive, irreversible part — firmware crypto + protocol — is **done**.
Everything between firmware and the user is stuck at v1, and v1 is **actively broken**.

| Layer | State | Evidence |
|---|---|---|
| device-protocol | ✅ Complete | messages 1600–1609 defined, SLIP-0048, `role` field (messages-hive.proto) |
| Firmware 7.15.0 | ✅ Complete | SLIP-0048 derive (hive.h:20-27, hive.c:42-46), 4 role keys (hive.c:58-83), account_create op 9 (hive.c:270-345), account_update op 10 (hive.c:352-426), on-device confirms + FSM wired (messagemap.def:183-193) |
| hdwallet | ⚠️ Half | `hiveGetPublicKey` + `hiveSignTx` only (hdwallet-keepkey/src/hive.ts:11-14). **Missing**: `hiveGetPublicKeys`, `hiveSignAccountCreate`, `hiveSignAccountUpdate` (1604–09). No SLIP-0048 helper. |
| Vault | ❌ v1 | `chains.ts` hive `defaultPath: [0x8000002C,0x800004FB,...]` = `m/44'/1275'/0'/0/0` (WRONG). `txbuilder/hive.ts` = transfer only. No onboarding UI/RPC. |
| Pioneer | ❌ Relay only | `hive.controller.ts`: account-by-pubkey, tx-params, history, broadcast. No create-account, no sponsor, no rate-limit. |

### The blocker bug (independent of onboarding)
Firmware's single-key handler derives exactly the path the host sends
(`fsm_msg_hive.h:22`). The vault sends `m/44'/1275'` — a path **no other Hive wallet
uses** (Ledger/Keychain/PeakD all use SLIP-0048 `m/48'/13'`). Result: the vault's STM
key is non-interoperable, and Pioneer's pubkey→account lookup can never match an account
made elsewhere. Any account funded against a v1 key is **unrecoverable in any other tool**.

→ The default-OFF settings flag (shipped, PR #293) is the correct holding position.
Hive must not reach a user until the path is fixed.

---

## 2. Phase 0 — Path fix (MANDATORY prerequisite, no onboarding yet)

Until this lands, nothing else is safe to ship. Breaking change is free: zero accounts
exist on v1 keys (flag has been off).

| Task | Layer | File | Size |
|---|---|---|---|
| `defaultPath` → `m/48'/13'/1'/0'/0'` (active role) | Vault | `shared/chains.ts` | S |
| Add `hiveRolePath(role, accountIndex)` helper | Vault | `shared/chains.ts` | S |
| Verify derived STM key == Hive Keychain output for same seed | — | device + Keychain | S |

**Exit check:** same KeepKey seed produces the **same** STM active key in vault and in
Hive Keychain. This is the single most important checkpoint in the whole effort.

---

## 3. Phase 1 — hdwallet plumbing (un-skippable for any onboarding)

The 3 proto messages exist but the JS wallet can't call them. Spec is fully written in
`HIVE-FIRMWARE-PLAN.md` Layer 2.

| Task | File | Size |
|---|---|---|
| Core interfaces: `HiveGetPublicKeys`, `HiveSignAccountCreate`, `HiveSignAccountUpdate` (+ Signed*) | hdwallet-core/src/hive.ts | S |
| `hiveSlip48Path()` + role constants | hdwallet-core/src/hive.ts | S |
| Wire shims 1604→1605, 1606→1607, 1608→1609 | hdwallet-keepkey/src/hive.ts | M |
| `keepkey.ts` methods: `hiveGetPublicKeys/hiveSignAccountCreate/hiveSignAccountUpdate` | hdwallet-keepkey/src/keepkey.ts | S |
| Submodule pin bump in vault after merge | vault | S |

**Exit check:** vault can call `hiveGetPublicKeys()` and get 4 STM keys from a real device.

---

## 4. Phase 2 — Sponsor service (the part with cost & ops)

This is what the "self-run" decision buys. **Economics first, code second.**

### 4a. How Hive account creation actually costs

Two on-chain ways to create an account:
- `account_create` — pays a flat **fee (currently ~3 HIVE)** per account. Cash out the door.
- `create_claimed_account` — spends a pre-claimed **Account Creation Token (ACT)**, which
you mint with **`claim_account`**. `claim_account` costs **either** 3 HIVE **or** a large
chunk of **Resource Credits (RC)** — and RC is free/regenerating if you've staked enough
**Hive Power (HP)**.

**The cheap model = stake HP → mint ACTs with RC on a schedule → spend ACTs for users.**
HP stake is **locked capital, not burned cash** (power-down returns it over 13 weeks).
Cash only bleeds if we fall back to the 3-HIVE fee during bursts.

> ⚠️ RC cost of `claim_account` and the creation fee are **witness-tunable** — do NOT
> hardcode. Read live values from the chain (`get_dynamic_global_properties`,
> `rc_api.get_resource_params`, witness `account_creation_fee`) and size HP from the
> measured claim rate you want to sustain. Capacity-plan before staking.

### 4b. Sponsor ops (Pioneer)

| Task | Detail | Size |
|---|---|---|
| Sponsor account + key mgmt | Funded Hive account; **active key in secrets, never in repo/.env-in-git**. Sign `claim_account` / `create_claimed_account` server-side. | M |
| ACT minting cron | Periodic `claim_account` while RC allows; maintain a pool of pending ACTs | M |
| `POST /hive/create-account` | Validate 4 STM keys, build+broadcast `create_claimed_account` from sponsor, return txid | M |
| `GET /hive/username-available/:name` | Format check + on-chain availability | S |
| `GET /hive/sponsor-info` | Pool size, RC %, HP, ACT count — for UI warnings + monitoring | S |
| Monitoring/alerts | Alert on ACT pool low / RC depleted / HP power-down | M |

### 4c. Abuse defense (a free-account faucet WILL be attacked)

| Control | Notes |
|---|---|
| Per-IP rate limit (1/24h baseline) | Pioneer has **no** rate-limit middleware today — must add (`express-rate-limit` or equiv) |
| **Device attestation** (our advantage) | Require a device-signed challenge so only a genuine KeepKey can request creation. Strong sybil defense competitors lack — lean on it instead of CAPTCHA. |
| Username blacklist + format validation | Reserved/abusive names |
| Pool circuit-breaker | Refuse when ACT pool/RC below threshold rather than fall back to cash fee silently |

**Exit check:** end-to-end on testnet/mainnet — device keys → username check → device
confirm → sponsor `create_claimed_account` → `@username` resolves and shows in vault.

---

## 5. Phase 3 — Vault onboarding UI

Spec in `HIVE-FIRMWARE-PLAN.md` Layer 4 (state machine + wizard steps). Net-new in vault.

| Task | File | Size |
|---|---|---|
| `txbuilder/hive-account.ts`: `buildHiveAccountCreate` / `buildHiveAccountUpdate` | vault/bun | M |
| RPCs: `hiveGetPublicKeys`, `hiveCreateAccount`, (later) `hiveSecureAccount` | vault/bun | M |
| Asset-page state machine: `NO_ACCOUNT / PENDING / ACTIVE / UNSECURED` | vault/mainview | M |
| Onboarding wizard (Flow A): intro → derive 4 keys → username → device confirm → broadcast → done | vault/mainview | L |
| Hive card: `@username` as address, send/receive | vault/mainview | M |

**Exit check:** a brand-new KeepKey with no Hive account completes the wizard and lands on
an ACTIVE Hive card, fully device-controlled.

---

## 6. Phase 4 — Migration (Flow B, "secure existing account") — optional

For users who already have a Hive account (most of them). Uses the already-implemented
`account_update`. Lets existing Keychain/Ledger users move custody to KeepKey.

- Vault migration wizard (warning → account name → show new keys → user signs with current
owner WIF in-memory once → device confirm `account_update` → done).
- Pioneer broadcasts `account_update` (broadcast path already exists).
- **Security:** owner WIF used in-memory for one broadcast, never stored/logged.

Lower priority than Phase 3 under the self-run decision, but cheap relative to the sponsor
work and high-value for adoption. Sequence after Phase 3 unless adoption data says otherwise.

---

## 7. Critical path & sequencing

```
Phase 0 (path fix) ─┬─→ Phase 1 (hdwallet) ─┬─→ Phase 2 (sponsor) ─→ Phase 3 (wizard) ─→ ship (flag on)
MANDATORY │ MANDATORY │ decision = yes new-user onboarding
│ └─→ Phase 4 (migration, optional, after P3)
└─ blocks everything; do first, verify against Keychain
```

Firmware/protocol: **0 work** (done). Heaviest remaining: Phase 2 (sponsor ops + abuse)
and Phase 3 (wizard UI). Capital: HP stake (recoverable). Recurring: ops + monitoring, plus
cash only if bursts exceed the ACT mint rate.

---

## 8. Decisions (resolved 2026-06-26)

1. **Gating → KeepKey owners only.** Creation requires a device-signed challenge; only a
genuine KeepKey can request. Near-sybil-proof, caps abuse and cost. (Phase 2 endpoint
must verify a device attestation, not just rate-limit.)
2. **Empty-pool policy → queue + circuit-breaker.** Refuse below a threshold and refill via
the mint cron; never silently fall back to the cash fee. No surprise spend.
3. **Multi-account → single account, index 0 only** for v1. `m/48'/13'/role'/0'/0'`.
Multi-account deferred (additive, non-breaking later).
4. **Key scope → active key only** for v1 (transfers, power up/down, staking). Posting-key
signing deferred. Smallest signing surface first.

### Still needs a number (not a blocker for Phase 0/1)
- **HP stake size** — driven by target accounts/day. With KeepKey-owners-only gating, volume
is bounded by device sales, so size the stake to that. Capacity-plan from live RC cost
before committing capital in Phase 2.
Loading
Loading