Release v1.2.15 → master#109
Merged
Merged
Conversation
Red gas pump icon appears on Dashboard chain cards when native balance < $1 USD but tokens on that chain exceed $1 — alerting users they need gas to move their tokens. SendForm gas hint also turns red with icon when gas is low.
Pioneer's ListUnspent expects the CAIP-2 networkId (e.g.
bip122:000000000000000000651ef99cb9fcbe for BCH), not the short chain
symbol ("BCH"). This caused "No UTXOs found" for all non-BTC UTXO
chains despite balances displaying correctly.
fix: pass networkId to Pioneer ListUnspent for BCH UTXOs
feat: low-gas warning on EVM chain cards
LTC/DOGE/BCH/DASH/DGB were deriving a single xpub and finding 0 UTXOs when funds sat on a different script type. Now mirrors BTC's multi-xpub pattern: derive all applicable xpubs (LTC gets p2pkh + p2sh-p2wpkh + p2wpkh; others get p2pkh) and pass allXpubs to buildUtxoTx for aggregation.
Pioneer API returns "relay" integration quotes (e.g. AVAX→ETH) with pre-built EVM transactions containing calldata — no THORChain-style memo or inbound vault needed. Previously these swaps failed with "Missing swap memo from quote" because the code assumed all swaps use memo-based routing. - Add RelayTxParams type for pre-built bridge transactions - Extract relay tx params (to, data, value, gas) in parseQuoteResponse - Skip memo/inboundAddress validation for relay integration - Add buildRelaySwapTx() that signs pre-built tx with fresh nonce - Pass integration + relayTx through frontend to executeSwap RPC
The let declaration was after the else block that assigns to it, causing a TDZ (temporal dead zone) error. Move it up next to the other buildTx locals (fromAddress, xpub).
…fallback 1. Guard relay chainId matches fromChain.chainId — prevents signing a tx for the wrong chain when a stale/mismatched quote is used. 2. Add Pioneer gas price fallback when RPC URL is absent, mirroring the normal EVM swap path (RPC → Pioneer → chain-specific gwei floor). Previously a relay tx could be built with no gas params at all.
getBalances and getBalance were still using a single xpub per non-BTC UTXO chain, so LTC funds on p2pkh or p2sh-p2wpkh addresses would show as 0 in the UI. Now derives all applicable xpubs in both balance paths, matching the buildTx aggregation fix.
fix: support relay bridge integration for cross-chain swaps
fix: aggregate UTXOs from all xpubs for non-BTC UTXO chains
Dashboard: add "LOW GAS" text label under the red gas pump icon. SendForm: replace inline hint with a full-width red warning banner showing icon, bold title, explanation text, and current gas balance.
These tax export formats produce empty reports — hide from UI until report data is populated. Backend code retained for future use.
…ubmodule pin
Pin firmware submodule to BitHighlander/keepkey-firmware release/7.14.0.
Add 3 selectable emulator channels:
- alpha: BitHighlander fork release/7.14.0 (latest dev)
- beta: BitHighlander fork release/7.14.0 (pre-release)
- release: upstream keepkey/keepkey-firmware master (stable)
Changes:
- manifest.json defines 3 channels with source repo/branch metadata
- emulator.ts supports channel-based dylib selection
- RPC schema adds emulatorGetChannels + channel param on emulatorInit
- EmulatorManager UI shows channel picker (alpha/beta/release buttons)
- Makefile adds build-emulator-{alpha,beta,release} targets
- download-emulators.ts script for fetching pre-built binaries
- docs/EMULATOR-CHANNELS.md SOP for release verification
When pairRawDevice times out on cold start, the retry loop spun forever because the WebUSB device stayed in opened state. Three fixes: 1. Close webUsbDevice on pair failure — resets opened flag so retries get a fresh connection instead of "already-connected" forever. 2. Cap retries at 24 (~2 min) then transition to error state with a clear message. retryCount resets on successful pairing. 3. Add retryConnect RPC + UI: clicking the KeepKey logo on the splash screen calls retryConnect (clears stale state, resets counter, re-syncs). After 10s of searching, "Tap to retry" hint fades in under the logo.
1. Don't wire onLogoClick during needs_pin or needs_passphrase states — retryConnect would blow away a legitimate unlock flow. 2. Only arm the "Tap to retry" timer when onLogoClick is provided — prevents dead affordance on claimed-state splash screen.
1. Channel not propagated through import/switch/restore:
- Added sticky `selectedChannel` that persists across stop/start cycles
- initEmulator() without explicit channel reuses the user's last selection
- Import, switch, and rollback flows now honor the selected channel
2. Beta is now a real pinned channel:
- Beta builds from BETA_PIN_SHA (specific commit), not branch tip
- Alpha tracks branch tip (moves), beta doesn't (manually promoted)
- Removed unused `autoUpdate` and top-level `channels` map from manifest
- manifest.json source entries now have { ref, type: "branch"|"commit" }
3. Download script verifies artifacts match declared source:
- Resolves declared ref to exact SHA before searching artifacts
- CI artifacts filtered by workflow_run.head_sha matching target SHA
- Release assets verified against target_commitish
- .build-sha recorded in channel dir for traceability
- Status command shows which SHA each channel was built from
… release builds
1. Import flow now honors channel selection on first use:
- Added channel param to emulatorImportWallet and emulatorSwitchWallet RPC schemas
- UI passes selectedChannel on import, start, and switch calls
- Backend forwards channel to initEmulator in all three paths
- Rollback path relies on sticky selectedChannel (already set by the explicit call)
2. Release-channel build works on fresh clones:
- _build-emu now ensures the keepkey remote exists before fetching
- .gitmodules configures origin as BitHighlander fork, so keepkey/master
would fail without this. The target adds the remote idempotently.
fix: USB pairing retry cap + manual retry via logo tap
feat: emulator channel selection (alpha/beta/release)
BIP-85 deterministic entropy is pushed back to the 7.15.0 firmware release. Updates all version gates and moves the BIP-85 changelog entry from 7.14.0 to a new 7.15.0 release section. Files changed: - firmware-versions.ts: move BIP-85 feature to 7.15.0 release entry - index.ts: setBip85Enabled gate + auto-disable check → 7.15.0 - Dashboard.tsx: BIP-85 icon visibility gate → 7.15.0 - DeviceSettingsDrawer.tsx: toggle gate + help text → 7.15.0
DeviceGrid was calling emulatorSwitchWallet without a channel parameter, causing initEmulator to fail with "No emulator dylib found for version default". The EmulatorManager had a proper channel picker but DeviceGrid bypassed it entirely. Now clicking Start on any emulator wallet (or Add Emulator) shows an inline channel picker (alpha/beta/release) before starting. Only installed channels are shown. Same pattern as the delete confirmation already used in the grid.
- Extract shared ChannelPicker into a local component used by both existing wallet cards and the "Add Emulator" card - Move channel colors to a module-level CHANNEL_COLORS record
fix: emulator start requires firmware channel selection
getEmulatorsDir() used __dirname which doesn't resolve correctly in Bun's bundled backend. Now tries multiple candidate paths (import.meta.dir at various depths, cwd-relative) and picks the first one containing manifest.json — same multi-fallback pattern as zcash-sidecar.
bundle-backend.ts marks @walletconnect/* as external (ESM/CJS dual-package
resolution breaks in Bun bundler), so require() happens at runtime. But
collect-externals.ts didn't include them, so the packages never made it
into the app bundle — runtime require('@walletconnect/core') failed,
crashing the backend before the logger initialized (black window).
This is why v1.2.11 had a black window while dev builds worked.
Adds an opt-in toggle that routes firmware/bootloader updates through the manifest's `beta` channel (already present in releases.json but previously unused). Separate from the existing preReleaseUpdates toggle which controls vault app updates — firmware has a different blast radius and deserves its own opt-in. - shared/types.ts: AppSettings.alphaFirmware - shared/rpc-schema.ts: setAlphaFirmware RPC method - bun/index.ts: DB-persisted (alpha_firmware key), wired to engine at startup and on toggle; syncState() re-derives needs_firmware_update against the new channel target - bun/engine-controller.ts: getChannelEntry() picks manifest.beta when opt-in (falls back to latest if beta missing); applyChannel() recomputes latestFirmware/latestBootloader; update URLs + hash verification now use the active channel - mainview/DeviceSettingsDrawer.tsx: toggle row under pre-release updates with distinct pink (#EC4899) accent and 🚧 icon Alpha testers flip the toggle → vault sees manifest.beta.firmware → needs_firmware_update lights up → flashes through the existing update flow with beta binary + hash verification.
1. Reconnect with pre-cached passphrase: if device reaches ready with passphraseProtection+passphraseCached but sendPassphrase() was not called this session, conservatively assume hidden wallet. Prevents disk leaks on app restart / reconnect to already-unlocked device. 2. hiddenWalletActive now set AFTER await sendPassphrase() succeeds — if user rejects on-device, the flag stays false (no misclassification). 3. passphraseSetThisSession flag distinguishes "we entered a passphrase" from "device had one pre-cached". Both cleared on disconnect. 4. isHiddenWallet exposed in DeviceStateInfo and getDeviceState() so frontend can react: TopNav badge only shows for actual hidden wallets, Reports button hidden when isHiddenWallet (backend already throws). 5. scanChainHistory error already displays inline in ActivityPanel via catch → setScanResult(e.message) — no additional UI change needed.
1. Reconnect hidden-wallet detection moved BEFORE this.emit('state-change')
so getDeviceState().isHiddenWallet is accurate on the first emit.
Frontend no longer gets stale isHiddenWallet: false on reconnect.
2. probeReconnectPassphraseState() resolves the false-positive for
standard-wallet reconnects: derives ETH address and compares against
stored seed_eth_{deviceId}. If it matches, reclassifies as standard
wallet and re-emits state-change. No DB writes, no seed-changed emit.
- Match → standard wallet (safe to cache, snapshot saved)
- Mismatch → confirmed hidden wallet (stays conservative)
- No stored identity → stays conservative (hidden wallet)
1. Session guard: probeReconnectPassphraseState() captures wallet ref +
deviceId before the async ethGetAddress call and verifies both still
match afterward. If the session changed (disconnect/reconnect/new
passphrase flow), the probe result is discarded — no stale mutations.
2. Missing seed identity no longer stays conservative. When no
seed_eth_{deviceId} is stored (fresh profile, DB reset, first run),
the probe derives the ETH address, stores it as the seed identity,
and reclassifies as standard wallet. This is safe because:
- First-time devices go through sendPassphrase() (sets flags correctly)
- Reconnect with cached empty passphrase = standard wallet by definition
- If it were actually a hidden wallet, there WOULD be a stored identity
from the original standard-wallet session that preceded it
…let leak
Reverts the "no stored = standard wallet" assumption. A missing
seed_eth_{deviceId} could mean first-time Vault launch with a device
already unlocked into a hidden wallet from another app. Writing the
hidden wallet's ETH address as canonical identity would both leak data
to disk and poison future standard/hidden classification.
Now: no stored identity = stay conservative (hidden wallet). Self-heals
on next normal connect cycle when sendPassphrase() sets flags correctly
and checkSeedIdentity() stores the standard wallet's ETH address.
…ase wallets
Three DB write paths leaked hidden wallet activity to disk:
1. insertApiLog() — 4 callsites: REST callback, broadcastTx, executeSwap,
chain history scan. Now guarded with isPassphraseWallet check. UI still
receives live log entries via RPC, just not persisted.
2. saveBip85Seed() — 2 callsites: getBip85Mnemonic (auto-save with label)
and saveBip85SeedMeta (explicit save). First silently skips, second throws
with a privacy explanation since it's a user-facing action.
3. insertSwapHistory() / updateSwapHistoryStatus() — swap-tracker.ts has no
direct access to engine, so added { skipPersist } option to trackSwap().
A noPersistSwaps Set tracks which txids should skip DB writes in the
polling loop. Swaps still track in-memory for UI status updates.
…wallet
When a device reconnects with passphraseCached=true but no seed_eth_*
identity in the DB (fresh install or DB reset), the probe previously
returned early and stayed in hidden-wallet mode indefinitely. This
disabled caching, reports, chain history, and showed hidden-wallet UI
for ordinary empty-passphrase standard wallets.
Fix: the probe now always derives the ETH address. When no stored
identity exists, it bootstraps — stores the current address as the
identity and reclassifies as standard wallet. If this is actually a
hidden wallet (edge case: first Vault launch with device already in a
hidden wallet from another app), the next proper connect via
sendPassphrase("") will run checkSeedIdentity, detect the mismatch,
and emit 'seed-changed' to correct the stored identity.
The bootstrap approach (store address + reclassify as standard on fresh DB) broke plausible deniability. A user under duress reconnecting with an empty passphrase needs the app to prove the device is empty — any trace written during an ambiguous session creates evidence. Reverted to conservative behavior: no stored identity = stay in hidden wallet mode, write nothing to disk. Standard wallet users on a fresh DB must re-enter their passphrase through Vault once to establish identity. This is a UX cost, not a privacy cost — and the right tradeoff for a hardware wallet with passphrase protection.
Read-side privacy gap: hidden wallet sessions could display stale standard-wallet data from the DB (cached balances, activity logs, swap history, reports, BIP-85 seeds). Now all read RPCs return empty results when isPassphraseWallet is true: - getCachedBalances → null - getApiLogs → [] - getRecentActivity → [] - listReports → [] - getSwapByTxid → null - getSwapHistory → [] - getSwapHistoryStats → zeroed - exportSwapReport → throws - listBip85Seeds → [] Dashboard shows a purple "passphrase wallet active" banner explaining that reports, history, and caching are disabled for privacy, with instructions to lock device and re-enter passphrase to restore features.
…ions; drop banner Remaining read-side gaps: - getReport / saveReportFile: report contents were accessible by ID even though listReports was blanked. Now return null / throw. - deleteReport: guarded to prevent modifying standard-wallet reports. - getPendingSwaps: rehydrated from SQLite, leaked standard-wallet pending swaps into hidden sessions. Now returns []. Removed the privacy banner — users who enabled passphrase protection in device settings understand the security model.
feat: passphrase wallet cache exemption
v1.2.11 Intel notarization failed because the x64 core downloaded from BitHighlander/electrobun tag v1.16.1-keepkey.1 pointed to commit 6d36b62f (GPU/WGPU contaminated) and its libNativeWrapper.dylib was "code object is not signed at all" — sign-release-intel couldn't re-sign it for notarization. Changes: 1. build-electrobun-x64-core.sh now adhoc-signs all x64 binaries after cross-compile, matching what the linker auto-does on arm64. Without adhoc signatures, subsequent Developer-ID signing fails. 2. CI build.yml FORK_TAG bumped to v1.16.1-keepkey.2 — new release built from commit 4f3d422a (safe, pre-GPU) with adhoc-signed binaries.
fix: rebuild electrobun x64 core from safe commit
i18next is configured with 14 namespaces (incl. swap, staking), but
non-English locales are each missing one of them — 9 locales lack
swap.json, 5 lack staking.json. On changeLanguage('es'), Vite's dynamic
import helper throws for the missing file, rejecting the
resourcesToBackend callback, which aborts the whole language switch.
UI silently stays in English.
Catch the import rejection and return an empty resource. i18next then
falls back to English for just that namespace (via fallbackLng) and
successfully switches language for everything else.
Previous fix swallowed every dynamic-import failure, which would hide real regressions (chunk load failures, malformed JSON, bad paths) as silent English fallbacks — much harder to detect in production. Match only Vite's specific "Unknown variable dynamic import" error (thrown when the path isn't in the generated import map, i.e. the translation file genuinely doesn't exist), warn once, and return an empty namespace. Rethrow everything else so real failures surface.
…builds Problem (raised during v1.2.12 retro): - arm64 is built + signed locally via `make build-signed` - Windows is built externally (no workflow for it here) - Only Intel x64 + Linux genuinely need CI - CI was uploading unsigned arm64 DMG/tar.zst + unsigned x86_64 DMG to the draft release. Any CI re-run (e.g. transient hdiutil failures) would clobber the locally-signed versions with unsigned ones. Changes: 1. Remove "Create unsigned DMG (macOS)" step — don't make an arm64 DMG 2. Remove "Create unsigned x86_64 DMG (macOS)" step — sign-release-intel builds the DMG from the signed tar.zst, an unsigned one just risks clobbering 3. New "Remove arm64 macOS artifacts" step after x64 variant is created — deletes all arm64 outputs (DMG, tar.zst, update.json, patches) so they never reach the release page CI still uploads: - stable-macos-x64-keepkey-vault.app.tar.zst (sign-release-intel consumes it) - Linux tar.zst + AppImage - SHA256SUMS.txt Never uploaded from CI: - KeepKey-Vault-X.Y.Z-arm64.dmg (local via make build-signed) - KeepKey-Vault-X.Y.Z-x86_64.dmg (local via make sign-release-intel) - stable-macos-arm64-* anything
ci: don't upload arm64 or unsigned x64 DMG — avoid clobbering signed builds
fix: language switch silently fails when namespace file missing
Switch from BitHighlander/electrobun fork to upstream blackboardsh/electrobun. Target macOS 13.0+ (Ventura) instead of 12.0 (Monterey). What changed: - .gitmodules: submodule URL → blackboardsh/electrobun, branch → main - Submodule pinned to upstream v1.16.0 - build-electrobun-x64-core.sh: target macOS 13.0, Bun 1.3.9 (was 1.1.20) - CI workflow: download x64 core from keepkey/keepkey-vault releases (tag: electrobun-x64-core-v1) instead of BitHighlander/electrobun fork Why: - The fork existed solely for resign-swizzle crash fix on macOS 12 Intel - macOS 13+ doesn't have the resign-swizzle issue - Eliminates: fork maintenance, GPU contamination risk, tag drift, fork-specific build.ts patches - x64 core still cross-compiled locally and published to our own releases
Finding #1 (High): CI downloads a hardcoded x64 core tag that can drift from the submodule. Added a CI gate that compares the submodule version against the release notes of the downloaded x64 core tag. Emits a ::warning if they don't match. Not a hard fail (to avoid blocking unrelated PRs) but visible in CI annotations. Finding #2 (Medium): Makefile publish-electrobun-x64-core still pointed at BitHighlander/electrobun. Updated to keepkey/keepkey-vault with new tag format (electrobun-x64-core-vN). Build script "Next steps" text also updated. All stale fork references removed.
feat: drop electrobun fork, use upstream + macOS 13+
Captures the diagnostic work from a 1.2.14 Windows install session for the next agent to act on. Three distinct failure modes, all surfacing to the user as the same "splash never advances" symptom but caused by unrelated bugs in different layers. 1. `Invalid Version: vundefined.undefined.undefined` on WebUSB pair — defensive fix in flight at keepkey/hdwallet#37 (with regression tests). Bumping the submodule pointer here is a follow-up after that PR merges. 2. Native crash on USB unplug during in-flight WebUSB write — bun process disappears with no JS error after libusb's `bad write`. Same family as the existing macOS attach-time SIGTRAP guard in engine-controller.ts:251-254. Open; suggested approach in the doc ranges from a process-supervisor band-aid to moving USB I/O into a child process. 3. Splash hangs forever when port 1646 is already bound — the FATAL exit message is in the backend log but the BrowserWindow is created before the port collision check, leaving an undecorated splash on screen. Open; fix is to move the collision probe before window creation and/or surface a "Vault is already running" UI state. Doc includes log evidence for each finding, root-cause file pointers, reproduction recipes, and an explicit "what is NOT broken" section to prevent the next agent from re-investigating the verified-intact download, the 1.2.14 @noble/hashes fix, the protobuf schema, and the frontend bundle.
docs: handoff for v1.2.14 Windows pair failures (3 findings)
…ation
THE BUG
=======
projects/keepkey-vault/src/bun/index.ts:4246 unconditionally spawned
`bash -c '<heartbeat watchdog script>'` at module load. On Win10, when
the app is launched from Explorer / Start Menu / installer Run-now,
the bun worker inherits an empty PATH from the parent process.
Bun.spawn delegates to libuv, which fails with UV_ENOENT (-4058) when
it can't locate `bash`, and the failure is delivered as an UNCAUGHT
asynchronous exception in the worker thread several seconds after the
spawn call site. The exception kills the entire app right around the
device pair flow, and the user sees a splash that hangs and then
disappears.
The watchdog is POSIX-only — its script uses bash, kill -9, date +%s,
sleep, cat — and could never have functioned on Windows even if `bash`
were on PATH. It exists to defend against an FFI freeze in
kkemu confirm_helper that only happens on macOS/Linux builds.
This was the dominant Win10 1.2.14 first-launch crash. Reproduced
twice across two different rebuilt 1.2.14 binaries (4f8ec1ba… and
2111ad61…), and verified fixed in-place by patching the installed
bundle and re-launching from the desktop icon.
THE FIX
=======
1. startHeartbeatWatchdog() returns early on process.platform === 'win32'
with a [Vault] Heartbeat watchdog skipped on Windows log line.
2. The Bun.spawn(['bash', ...]) call is wrapped in try/catch as
defense-in-depth on POSIX hosts where bash could conceivably be
missing (containers, minimal NixOS, etc).
3. A long comment block above the function explains the platform
constraint and references this incident, so the next person to
touch the watchdog doesn't accidentally re-enable it on Windows.
OBSERVABILITY (the only reason this was diagnosable)
====================================================
The previous logger used fs.createWriteStream(LOG_FILE, {flags:'a'})
whose buffered .write() calls never reached disk on a worker-thread
crash. Every failed launch left a vault-backend.log that "ended" 2-7
seconds before the actual death point, and we spent two days chasing
wrong root causes (libusb segfault, semver throw, port collision)
because the actual exception line never made it to disk.
This commit replaces the buffered stream with fs.appendFileSync per
log call. Throughput hit is negligible at our log volume (~10-100
lines/sec at peak boot); the upside is that the log file is now a
faithful record of what executed up to a crash.
It also adds a structured boot environment dump immediately after
[Boot] Log file: …, capturing platform, arch, pid, ppid, cwd, argv,
stdio TTY status, PATH.length, LANG, LC_ALL, and Windows-only env
vars (USERNAME, SESSIONNAME, APPDATA, LOCALAPPDATA). The PATH.length
field is what surfaced this bug — Explorer launches show
PATH.length=0, terminal launches show PATH.length=882. Without that
single field, the only evidence was "splash hangs" which is
consistent with twenty different root causes.
Finally, engine-controller.ts gets boundary log lines around every
JS↔native transition in start() and fetchFirmwareManifest() —
usb.on(attach), usb.on(detach), usb.getDeviceList(), mergeManifests,
applyChannel, syncState — each wrapped in try/catch with an explicit
[Engine] FATAL: log so a future libusb segfault leaves a clear
breadcrumb instead of a silent process exit.
WHAT THIS DOES NOT FIX
======================
The three findings from docs/HANDOFF-1.2.14-WINDOWS-PAIR.md remain:
- Finding 1 (Invalid Version: vundefined.undefined.undefined) is
addressed by keepkey/hdwallet#37 which still needs review/merge,
followed by a submodule pointer bump here.
- Finding 2 (native crash on USB unplug during pairRawDevice) is
separate from this PR's bug. With the sync logger landing, the
next reproduction should leave the actual death cause in the log.
- Finding 3 (port-1646 collision splash hang) is already fixed in
the official 1.2.14 rebuild from 2026-04-09 — verified working.
See docs/HANDOFF-1.2.14-WIN10-WATCHDOG-CRASH.md for the full
diagnosis story, including the verification recipe.
fix(win10): skip POSIX heartbeat watchdog on Windows + sync logging foundation
Bump version to 1.2.15 and pin hdwallet submodule to master (includes keepkey/hdwallet#37 — Features version validation). Changes since v1.2.14 pre-release: - fix(win10): skip POSIX heartbeat watchdog on Windows (#107) - fix: sync file logger — crash logs now survive native exceptions (#107) - fix: boot environment dump for launch-context diagnostics (#107) - fix: JS↔native boundary logging in engine-controller (#107) - fix: port 1646 collision check before window creation (#106) - fix: USB detach race guard on WebUSB pair (#106) - fix: hdwallet Features version validation (hdwallet#37) - docs: handoff for 1.2.14 Windows pair failures (#105) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
electrobun.config.ts had a hardcoded version (1.2.11) that drifted from package.json. Import pkg.version so they can never diverge — the signed artifact, installer name, and updater version all read from one source. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Release v1.2.15 — Windows 10 fixes + observability
Tab buttons (Apps, ShapeShift, Settings) were inside the electrobun-webkit-app-region-drag zone without the no-drag opt-out class, so clicks were swallowed by the window drag handler on Linux and macOS. Blockchain items worked because they're in the Dashboard, outside the drag region. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Merge develop into master for v1.2.15 release.
Changes since last master merge
Release: https://github.com/keepkey/keepkey-vault/releases/tag/v1.2.15