iuna

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

commit 6c5bda1fe4a901840e503feac11e7372a58e94aa
parent c71fd75ad36b2a12ff91de5335b9b670fb5326a9
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Fri, 24 Jul 2026 11:34:37 +0200

Fix advanced UTXO transfer form

Diffstat:
Massets/luun-ui.js | 14+++++++++++---
Msrc/adapters/http.rs | 27+++++++++++++--------------
2 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/assets/luun-ui.js b/assets/luun-ui.js @@ -434,9 +434,17 @@ window.luunApp = function luunApp() { headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" }, body, }); - const payload = await response.json(); + const text = await response.text(); + let payload = { ok: response.ok, error: null }; + if (text) { + try { + payload = JSON.parse(text); + } catch { + payload = { ok: false, error: text }; + } + } if (!response.ok || !payload.ok) { - throw new Error(payload.error || `${path} returned ${response.status}`); + throw new Error(payload?.error || `${path} returned ${response.status}`); } await this.refresh(); this.showFlash(successMessage, "success"); @@ -546,7 +554,7 @@ window.luunApp = function luunApp() { const recipient = this.short(this.transferTo); await this.postForm( "/api/transfer", - { to: this.transferTo, amount, fee, utxos: this.selectedTransferUtxos }, + { to: this.transferTo, amount, fee, utxos: this.selectedTransferUtxos.join("\n") }, `Queued transfer of ${this.amountLabel(amount)} LUUN to ${recipient} with ${this.amountLabel(fee)} fee` ); this.transferTo = ""; diff --git a/src/adapters/http.rs b/src/adapters/http.rs @@ -52,7 +52,7 @@ struct TransferForm { amount: Amount, fee: Option<Amount>, #[serde(default)] - utxos: Vec<String>, + utxos: String, } #[derive(Debug, Deserialize)] @@ -774,9 +774,11 @@ fn validate_transfer_form(form: TransferForm) -> Result<(String, Amount, Amount, let fee = form.fee.context("fee is required")?; let selected_utxos = form .utxos - .iter() + .lines() + .flat_map(|line| line.split(',')) + .map(str::trim) .filter(|value| !value.trim().is_empty()) - .map(|value| parse_outpoint(value)) + .map(parse_outpoint) .collect::<Result<Vec<_>>>()?; Ok((to.to_string(), form.amount, fee, selected_utxos)) } @@ -910,11 +912,12 @@ const INDEX_HTML: &str = r#"<!doctype html> .setup-status { border: 1px solid #566d25; border-radius: 8px; padding: 10px; background: #1c2516; color: #d5f55f; font-weight: 800; } .wallet-grid { width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, .8fr); gap: 12px; align-items: start; } .wallet-actions { display: grid; gap: 12px; } - .advanced-toggle { justify-self: start; border: 0; padding: 0; background: transparent; color: #d5f55f; } + .advanced-toggle { flex-basis: 100%; width: max-content; align-self: flex-start; border-color: #3a4248; padding: 4px 7px; background: #202328; color: #9fa8ad; font-size: 12px; } + .advanced-toggle:hover { border-color: #5a646b; color: #d6dee2; } .send-utxo-list { display: grid; gap: 8px; max-height: 260px; overflow: auto; border: 1px solid #2f363c; border-radius: 8px; padding: 8px; background: #111316; } .send-utxo-option { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px; align-items: start; border: 1px solid #2f363c; border-radius: 8px; padding: 8px; background: #181b1f; } .send-utxo-option input { min-width: auto; margin-top: 3px; } - .send-utxo-summary { display: grid; gap: 5px; color: #9eb3bc; font-size: 13px; } + .send-utxo-summary { flex-basis: 100%; width: 100%; display: grid; gap: 5px; color: #9eb3bc; font-size: 13px; } .wallet-balance-line { display: inline-grid; grid-template-columns: auto auto; gap: 10px; align-items: baseline; padding: 8px 10px; border: 1px solid #2f363c; border-radius: 8px; background: #111316; color: inherit; cursor: pointer; } .wallet-balance-line:hover, .wallet-balance-line:focus-visible { border-color: #d5f55f; outline: none; } .wallet-balance-line .tx-value { font-size: 16px; font-weight: 850; } @@ -1575,7 +1578,7 @@ mod tests { to: " ".to_string(), amount: 1, fee: Some(1), - utxos: Vec::new(), + utxos: String::new(), }) .unwrap_err(); assert!(error.to_string().contains("recipient is required")); @@ -1584,7 +1587,7 @@ mod tests { to: "abc".to_string(), amount: 0, fee: Some(1), - utxos: Vec::new(), + utxos: String::new(), }) .unwrap_err(); assert!( @@ -1597,7 +1600,7 @@ mod tests { to: "abc".to_string(), amount: 1, fee: None, - utxos: Vec::new(), + utxos: String::new(), }) .unwrap_err(); assert!(error.to_string().contains("fee is required")); @@ -1609,7 +1612,7 @@ mod tests { to: " abc ".to_string(), amount: 2, fee: Some(3), - utxos: Vec::new(), + utxos: String::new(), }) .unwrap(); @@ -1625,11 +1628,7 @@ mod tests { to: "abc".to_string(), amount: 2, fee: Some(3), - utxos: vec![ - "tx-one:0".to_string(), - "tx:with:colons:7".to_string(), - "".to_string(), - ], + utxos: "tx-one:0\ntx:with:colons:7,\n".to_string(), }) .unwrap();