iuna

iuna - experimental devnet protocol
git clone https://iuna.jhx.app/git/iuna.git
Log | Files | Refs | README | LICENSE

commit 9847a52accc3a764803f92bc0a2bdaf723eee9e8
parent 7874213250a9dcde8a94dd972f5b3e971f727919
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Wed, 22 Jul 2026 21:53:37 +0200

Clarify wallet setup recovery phrase

Diffstat:
Msrc/adapters/http.rs | 36+++++++++++++++++++++++++-----------
Msrc/adapters/wallet_store.rs | 13+++++++------
2 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/src/adapters/http.rs b/src/adapters/http.rs @@ -496,6 +496,11 @@ const INDEX_HTML: &str = r#"<!doctype html> .setup-feedback.error { color: #ffb1a8; background: #2a1717; border-color: #713434; } .setup-grid { width: 100%; display: grid; grid-template-columns: minmax(0, .9fr) minmax(320px, .7fr); gap: 12px; align-items: start; } .setup-section { border: 1px solid #2f363c; border-radius: 8px; padding: 13px; background: #111316; } + .setup-field { display: grid; gap: 6px; } + .setup-field-label { color: #8d989f; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: 0; } + .setup-address-box { display: flex; justify-content: space-between; gap: 10px; align-items: center; } + .setup-address-box code { min-width: 0; } + .setup-address-box button { flex: 0 0 auto; } .setup-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 14px; } .setup-peer-list { margin-top: 14px; display: grid; gap: 8px; } .setup-peer-row { display: flex; justify-content: space-between; gap: 12px; align-items: center; border: 1px solid #2f363c; border-radius: 8px; padding: 10px; background: #181b1f; } @@ -503,7 +508,7 @@ const INDEX_HTML: &str = r#"<!doctype html> .segmented button { border-color: transparent; background: transparent; color: #9fa8ad; } .segmented button.active { background: #d5f55f; color: #15171a; } .seed-panel { display: grid; gap: 12px; } - .seed-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 8px; } + .seed-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; } .seed-word { display: grid; grid-template-columns: 30px minmax(0, 1fr); gap: 7px; align-items: center; border: 1px solid #2f363c; border-radius: 6px; padding: 7px 8px; background: #181b1f; } .seed-word .index { color: #8d989f; font-size: 11px; font-weight: 800; } .seed-word .word { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-weight: 800; color: #c7f5ea; } @@ -574,6 +579,7 @@ const INDEX_HTML: &str = r#"<!doctype html> header { display: grid; } input { min-width: 0; width: 100%; } .switch input { width: auto; } + .seed-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .block-card { flex-basis: 108px; } } </style> @@ -806,23 +812,31 @@ const INDEX_HTML: &str = r#"<!doctype html> <div class="setup-section seed-panel"> <div class="panel-head"> <h3>Wallet</h3> - <button type="button" @click="copyAddress">Copy</button> </div> - <div class="address-box"><code x-text="setupAddress()"></code></div> <div class="segmented" role="tablist" aria-label="Wallet setup mode"> <button type="button" :class="{ active: setupWalletMode === 'create' }" @click="selectSetupWalletMode('create')">Create</button> <button type="button" :class="{ active: setupWalletMode === 'import' }" @click="selectSetupWalletMode('import')">Import</button> </div> <div x-show="setupWalletMode === 'create'" class="seed-panel"> + <div class="setup-field"> + <div class="setup-field-label">Address</div> + <div class="address-box setup-address-box"> + <code x-text="setupAddress()"></code> + <button type="button" @click="copyAddress">Copy</button> + </div> + </div> <template x-if="setupSeedWords().length > 0 && setupSeedStep === 'write'"> <div class="seed-panel"> - <div class="seed-grid"> - <template x-for="(word, index) in setupSeedWords()" :key="index"> - <div class="seed-word"> - <span class="index" x-text="index + 1"></span> - <span class="word" x-text="word"></span> - </div> - </template> + <div class="setup-field"> + <div class="setup-field-label">Recovery phrase</div> + <div class="seed-grid"> + <template x-for="(word, index) in setupSeedWords()" :key="index"> + <div class="seed-word"> + <span class="index" x-text="index + 1"></span> + <span class="word" x-text="word"></span> + </div> + </template> + </div> </div> <div class="setup-actions"> <button type="button" class="subtle" @click="generateSetupSeed">Regenerate</button> @@ -859,7 +873,7 @@ const INDEX_HTML: &str = r#"<!doctype html> </div> <div x-show="setupWalletMode === 'import'" class="seed-panel"> <form @submit.prevent="importSetupSeed"> - <label>Recovery phrase<textarea x-model="importSeedPhrase" autocomplete="off" spellcheck="false"></textarea></label> + <label>Recovery phrase<textarea x-model="importSeedPhrase" autocomplete="off" spellcheck="false" placeholder="24 words, separated by spaces or new lines"></textarea></label> <button class="primary" type="submit">Import</button> </form> <template x-if="walletVerified"> diff --git a/src/adapters/wallet_store.rs b/src/adapters/wallet_store.rs @@ -11,7 +11,6 @@ use crate::domain::Wallet; const WALLET_FILE_VERSION: u32 = 2; const GENERATED_SEED_WORDS: usize = 24; -const IMPORT_SEED_WORD_COUNTS: [usize; 2] = [12, 24]; const SEED_WORDS: &[&str] = &[ "able", "acid", "acorn", "adapt", "agent", "anchor", "angle", "apple", "asset", "atlas", "badge", "balance", "beacon", "benefit", "binary", "bitter", "blanket", "border", "brave", @@ -170,8 +169,8 @@ fn normalize_seed_phrase(seed_phrase: &str) -> Result<String> { .map(|word| word.trim().to_ascii_lowercase()) .filter(|word| !word.is_empty()) .collect::<Vec<_>>(); - if !IMPORT_SEED_WORD_COUNTS.contains(&words.len()) { - bail!("seed phrase must contain 12 or 24 words"); + if words.len() != GENERATED_SEED_WORDS { + bail!("seed phrase must contain 24 words"); } for word in &words { if !word.chars().all(|ch| ch.is_ascii_lowercase()) { @@ -297,7 +296,7 @@ mod tests { let wallet = replace_with_imported_seed_phrase( &path, - " Able ACID acorn adapt agent anchor angle apple asset atlas badge balance ", + " Able ACID acorn adapt agent anchor angle apple asset atlas badge balance beacon benefit binary bitter blanket border brave bright broker budget cactus canvas ", ) .unwrap(); let loaded = load_or_create(&path).unwrap(); @@ -305,7 +304,9 @@ mod tests { assert_eq!(wallet.address(), loaded.address()); assert_eq!( setup_seed_phrase(&path).unwrap().as_deref(), - Some("able acid acorn adapt agent anchor angle apple asset atlas badge balance") + Some( + "able acid acorn adapt agent anchor angle apple asset atlas badge balance beacon benefit binary bitter blanket border brave bright broker budget cactus canvas" + ) ); } @@ -316,7 +317,7 @@ mod tests { let error = replace_with_imported_seed_phrase(&path, "too few words").unwrap_err(); - assert!(error.to_string().contains("12 or 24 words")); + assert!(error.to_string().contains("24 words")); } fn assert_recovery_words_verify(seed_phrase: &str, indexes: &[usize]) {