aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-11-06 23:28:09 -0700
committerAdam Soltys <[email protected]>2026-11-06 23:28:09 -0700
commit4c8754a843335bfa4d84a989fb92f33bc6c26367 (patch)
treec2341a12b2585ac42b82947ea5cf84c79963bba8
parent9ffdeacf18ab2b6ff2344e1ec5cf0a085b18325b (diff)
downloadcoinosv3-4c8754a843335bfa4d84a989fb92f33bc6c26367.tar.gz
coinosv3-4c8754a843335bfa4d84a989fb92f33bc6c26367.zip
The seed-phrase pages say less: no "write these 12 words down on paper" box, the passphrase behind "Add passphrase", and the import titled "Enter seed phrase". Adam, 2026-11-06: the warning box goes from the create pane and the backup step (the words and the page's own title carry it); the BIP39 passphrase field, which read as a required password under the seed, waits behind an "Add passphrase" button and, opened, is labelled "Passphrase (optional)" with "Leave it empty unless you want one. Most wallets have none." (What's this? still explains it; a typed passphrase keeps it open; clearing the drafts closes it). The import pane is titled "Enter seed phrase" (was "Restore your wallet"), its field "Seed phrase" (was "Recovery phrase or key") with the placeholder "Your seed words" — an xpub or xprv pasted there still opens as before. tools/onboard-backup-test.js follows the new words
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6Ts5Tktega8VbLg31q
-rw-r--r--src/app.js22
-rw-r--r--src/i18n.js9
-rw-r--r--tools/onboard-backup-test.js12
3 files changed, 26 insertions, 17 deletions
diff --git a/src/app.js b/src/app.js
index fff5b04..5b57f37 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1502,7 +1502,6 @@ function createPane() {
return h(
'div',
{ class: 'col' },
- h('div', { class: 'warn-box' }, t('writeDownWarn')),
h(
'div',
{ class: 'words', style: '--rows-3:' + Math.ceil(words.length / 3) + ';--rows-2:' + Math.ceil(words.length / 2) },
@@ -1630,7 +1629,7 @@ function entropyPage() {
// tabs, backing out of the entropy page, going home. Whatever you come back
// to is empty. (An opened wallet clears these too, in openWallet/lock.)
function clearSeedDrafts() {
- ui.importText = ''; ui._entropyFilled = null;
+ ui.importText = ''; ui._entropyFilled = null; ui.passOpen = false;
ui.entropyEntry = ''; ui.ownEntropy = ''; ui.importEntropy = '';
}
@@ -1668,18 +1667,28 @@ function importPane() {
}
function optionsPanel() {
+ // Most people want no passphrase, and an empty field labelled "Passphrase"
+ // under the seed reads as a required password. It waits behind a button,
+ // and once opened says it's optional (Adam, 2026-11-06). A passphrase
+ // already typed keeps it open.
+ if (!ui.passOpen && !ui.passphrase) {
+ return [h('button', {
+ class: 'btn-ghost btn-sm', type: 'button', style: 'align-self:flex-start',
+ onClick: (e) => { e.preventDefault(); ui.passOpen = true; render(); },
+ }, t('addPassphrase'))];
+ }
const pass = h(
'label',
{ class: 'field' },
h('span', { class: 'lab' },
- t('passphrase'),
+ t('passphraseOptional'),
// People assume a password logs in or encrypts; a BIP39 passphrase does
// neither, and getting that wrong loses money — worth a sentence here.
h('button', {
class: 'linklike small', type: 'button', style: 'margin-left:8px',
onClick: (e) => { e.preventDefault(); ui.passInfoOpen = !ui.passInfoOpen; render(); },
}, t('passWhatsThis'))),
- ui.passInfoOpen ? h('p', { class: 'small muted', style: 'margin:0 0 6px' }, t('passInfo')) : null,
+ ui.passInfoOpen ? h('p', { class: 'small muted', style: 'margin:0 0 6px' }, t('passInfo')) : h('p', { class: 'small muted', style: 'margin:0 0 6px' }, t('passOptionalHint')),
h(
'div',
{ class: 'input-group' },
@@ -2800,7 +2809,7 @@ function lock({ offerPassword = false } = {}) {
ui.entropyEntry = '';
ui.ownEntropy = '';
ui.importEntropy = '';
- ui.passphrase = '';
+ ui.passphrase = ''; ui.passOpen = false;
ui.confirmPass = '';
ui.confirm = [];
ui.revealShown = false;
@@ -3484,7 +3493,7 @@ function accountsScreen() {
if (aw.from === 'new') {
ui.newWalletKind = kind;
ui.addWallet = null;
- ui.draftMnemonic = ''; ui.createStep = 'gen'; ui.confirm = []; ui.passphrase = ''; ui.confirmPass = '';
+ ui.draftMnemonic = ''; ui.createStep = 'gen'; ui.confirm = []; ui.passphrase = ''; ui.confirmPass = ''; ui.passOpen = false;
ui.showPass = false; ui.screen = 'unlock'; ui.unlockTab = 'create'; ui.fromWallet = true; ui.unlockError = '';
render();
} else {
@@ -4285,7 +4294,6 @@ function onboardScreen() {
return page([
title(t('onbBackupTitle')),
h('p', { class: 'muted', style: 'margin:0' }, t('onbBackupBody')),
- h('div', { class: 'warn-box' }, t('writeDownWarn')),
h('div', { class: 'words', style: '--rows-3:' + Math.ceil(words.length / 3) + ';--rows-2:' + Math.ceil(words.length / 2) }, words.map((w, i) =>
h('div', { class: 'w' }, h('span', { class: 'n' }, i + 1), h('span', { class: 't' }, w)))),
h('div', { class: 'row gap6' }, copyBtn(acc.mnemonic, t('copyPhrase'))),
diff --git a/src/i18n.js b/src/i18n.js
index a6aafdb..ecf0363 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -208,12 +208,15 @@ const STR = {
seedPlaceholder: 'enter your seed words separated by spaces',
passphrase: 'Passphrase',
passWhatsThis: 'What’s this?',
+ addPassphrase: 'Add passphrase',
+ passphraseOptional: 'Passphrase (optional)',
+ passOptionalHint: 'Leave it empty unless you want one. Most wallets have none.',
passInfo: 'An optional 13th word: if someone gets hold of your 12 seed words, they still can’t open your wallet without this one. It’s not a login password and it doesn’t encrypt anything: each passphrase opens its own separate wallet, so to recover your funds you’ll need your seed words and this passphrase, exactly as written.',
show: 'Show',
hide: 'Hide',
invalidSeed: 'Invalid seed phrase. Check the spelling and word order.',
- importLabel: 'Recovery phrase or key',
- importPlaceholder: 'Your seed words, or an xpub / xprv',
+ importLabel: 'Seed phrase',
+ importPlaceholder: 'Your seed words',
invalidImport: 'That is not a valid recovery phrase, xpub, or xprv.',
importedKey: 'Imported key',
importedKeyNote: 'This wallet was imported from an extended private key, so there is no recovery phrase. Back up that key itself to keep the wallet.',
@@ -1401,7 +1404,7 @@ const STR = {
backupReminder: 'Your recovery phrase is still unwritten.',
backupReminderGo: 'Write it down',
onbSeedTitle: 'Set up your wallet',
- onbRestoreTitle: 'Restore your wallet',
+ onbRestoreTitle: 'Enter seed phrase',
onbRestoreDoor: 'Sign in with seed phrase',
onbSignInExisting: 'Sign in to an existing account',
onbSigninTitle: 'Sign in',
diff --git a/tools/onboard-backup-test.js b/tools/onboard-backup-test.js
index 3433271..c7221fd 100644
--- a/tools/onboard-backup-test.js
+++ b/tools/onboard-backup-test.js
@@ -87,12 +87,10 @@ try {
// words on screen at once, with what they are.
await page.evaluate(() => document.getElementById('onb-create')?.click());
await sleep(600);
- const made = await page.evaluate(() => ({
- words: document.querySelectorAll('.words .w .t').length,
- says: /12 words|twelve words/i.test(document.body.innerText),
- }));
- check('the way in shows what the wallet actually is: its twelve words', made.words === 12 && made.says,
- made.words + ' words' + (made.says ? ', explained' : ', unexplained'));
+ // the warning box that said "write these 12 words down" is gone
+ // (2026-11-06): the words themselves are the explanation
+ const made = await page.evaluate(() => document.querySelectorAll('.words .w .t').length);
+ check('the way in shows what the wallet actually is: its twelve words', made === 12, made + ' words');
await page.close();
}
@@ -120,7 +118,7 @@ try {
await page.evaluate(() => document.getElementById('onb-restore')?.click());
await sleep(600);
const pane = await page.evaluate(() => ({
- title: /restore your wallet/i.test(document.body.innerText),
+ title: /enter seed phrase/i.test(document.body.innerText),
field: !!document.querySelector('textarea[placeholder*="seed words" i]'),
minted: document.querySelectorAll('.words .w .t').length,
}));