iuna

iuna

iuna - experimental mainnet-candidate protocol
git clone https://getiuna.org/git/iuna.git
Log | Files | Refs | README | LICENSE

commit 1b900bbc729849ec1539ddb11cd93c5e83913e86
parent babc1d549d5ce2c0aa28baa0fcba347e470c51a8
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Wed,  9 Sep 2026 12:06:39 +0200

fix(wallet): show all transaction types by default

Diffstat:
Msrc/adapters/http/types.rs | 8++++----
Msrc/main_tests.rs | 18++++++++++++++++++
Mwallet/app.js | 28++++++++++++++++------------
Mwww/assets/iuna-ui.js | 2+-
4 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/src/adapters/http/types.rs b/src/adapters/http/types.rs @@ -248,8 +248,8 @@ impl Default for WalletTransactionFilters { fn default() -> Self { Self { transfer: true, - mine: false, - burn: false, + mine: true, + burn: true, reward: true, } } @@ -259,8 +259,8 @@ impl WalletTransactionFilters { pub(super) fn from_query(query: WalletTransactionsQuery) -> Self { Self { transfer: query.tx.unwrap_or(true), - mine: query.mine.unwrap_or(false), - burn: query.burn.unwrap_or(false), + mine: query.mine.unwrap_or(true), + burn: query.burn.unwrap_or(true), reward: query.reward.unwrap_or(true), } } diff --git a/src/main_tests.rs b/src/main_tests.rs @@ -211,6 +211,24 @@ fn management_ui_wallet_transactions_share_the_generic_detail_flow() { assert!(javascript.contains("outpoint: { txid: input.signature, index: \"fee\" }")); } +#[test] +fn transaction_filters_default_to_every_transaction_type() { + let management_javascript = include_str!("../www/assets/iuna-ui.js"); + let wallet_javascript = include_str!("../wallet/app.js"); + let all_filters = "{ transfer: true, mine: true, burn: true, reward: true }"; + + assert!(management_javascript.contains(&format!("walletTxFilters: {all_filters}"))); + assert!(wallet_javascript.contains(&format!("const ALL_TRANSACTION_FILTERS = {all_filters}"))); +} + +#[test] +fn lightweight_wallet_recent_activity_does_not_use_view_all_filters() { + let javascript = include_str!("../wallet/app.js"); + + assert!(javascript.contains("api(transactionPath(0, 5, ALL_TRANSACTION_FILTERS))")); + assert!(javascript.contains("activityList(5, false, state.recentTransactions)")); +} + fn ledger_with_one_spendable_iuna(wallet: &Wallet) -> Ledger { let mut genesis = BTreeMap::new(); genesis.insert(wallet.address().to_string(), 3); diff --git a/wallet/app.js b/wallet/app.js @@ -8,10 +8,11 @@ import { generateMnemonic, validateMnemonic } from "./mnemonic.js"; const app = document.querySelector("#app"); const toastElement = document.querySelector("#toast"); const TRANSACTION_PAGE_SIZE = 25; +const ALL_TRANSACTION_FILTERS = { transfer: true, mine: true, burn: true, reward: true }; const state = { store: null, wallet: null, walletMeta: null, status: null, address: "", balance: null, - utxos: [], transactions: [], view: "home", timer: null, - transactionFilters: { transfer: true, mine: false, burn: false, reward: true }, + utxos: [], transactions: [], recentTransactions: [], view: "home", timer: null, + transactionFilters: { ...ALL_TRANSACTION_FILTERS }, transactionPage: { offset: 0, total: 0, hasMore: true, loading: false, error: "" }, transactionRequest: 0, activityObserver: null, @@ -136,6 +137,7 @@ async function fetchWalletData() { const address = encodeAddress(state.wallet.publicKey, state.status.chain_id); if (state.address && state.address !== address) { state.transactions = []; + state.recentTransactions = []; Object.assign(state.transactionPage, { offset: 0, total: 0, hasMore: true, loading: false, error: "" }); } state.address = address; @@ -144,25 +146,27 @@ async function fetchWalletData() { const transactionLimit = Math.min(100, Math.max(TRANSACTION_PAGE_SIZE, previousTransactionCount)); const refreshTransactions = !state.transactionPage.loading; const transactionRequest = refreshTransactions ? ++state.transactionRequest : null; - const [balance, utxos, transactions] = await Promise.all([ + const [balance, utxos, transactions, recentTransactions] = await Promise.all([ api(`/addresses/${encoded}/balance`), api(`/addresses/${encoded}/utxos`), refreshTransactions ? api(transactionPath(0, transactionLimit)) : Promise.resolve(null), + api(transactionPath(0, 5, ALL_TRANSACTION_FILTERS)), ]); state.balance = balance; state.utxos = utxos.utxos || []; + state.recentTransactions = Array.isArray(recentTransactions?.items) ? recentTransactions.items : []; if (transactions && transactionRequest === state.transactionRequest) { applyTransactionPage(transactions, true, previousTransactionCount); } } -function transactionPath(offset, limit) { +function transactionPath(offset, limit, filters = state.transactionFilters) { const encoded = encodeURIComponent(state.address); const params = new URLSearchParams({ - tx: String(state.transactionFilters.transfer), - mine: String(state.transactionFilters.mine), - burn: String(state.transactionFilters.burn), - reward: String(state.transactionFilters.reward), + tx: String(filters.transfer), + mine: String(filters.mine), + burn: String(filters.burn), + reward: String(filters.reward), offset: String(offset), limit: String(limit), }); @@ -290,9 +294,9 @@ function formatTransactionDate(item) { }).replace(",", ""); } -function activityList(limit, filtered = false) { - const items = typeof limit === "number" ? state.transactions.slice(0, limit) : state.transactions; - if (!items.length && state.transactionPage.loading) return ''; +function activityList(limit, filtered = false, source = state.transactions) { + const items = typeof limit === "number" ? source.slice(0, limit) : source; + if (!items.length && filtered && state.transactionPage.loading) return ''; if (!items.length) return filtered ? '<div class="empty">No transactions match these filters.</div>' : '<div class="empty">No transactions yet.<br>Your new wallet is ready to use.</div>'; @@ -305,7 +309,7 @@ function activityList(limit, filtered = false) { function renderHome() { const readonly = state.walletMeta?.type === "readonly"; - return `${topbar()}<section>${readonly ? '<div class="mode-badge">Watch-only · signing disabled</div>' : ""}<p class="eyebrow">Available balance</p><h1 class="balance">${formatIuna(state.balance?.spendable, 6)} <span>IUNA</span></h1><p class="subbalance">${formatIuna(state.balance?.confirmed, 6)} confirmed · block ${escapeHtml(state.balance?.height)}</p><div class="actions"><button class="button" data-view="send" ${readonly ? "disabled" : ""}>${icon("send")} Send</button><button class="button secondary" data-view="receive">${icon("receive")} Receive</button></div><div class="section-head"><h2>Recent activity</h2><button data-view="activity">View all</button></div><div class="panel">${activityList(5)}</div></section>`; + return `${topbar()}<section>${readonly ? '<div class="mode-badge">Watch-only · signing disabled</div>' : ""}<p class="eyebrow">Available balance</p><h1 class="balance">${formatIuna(state.balance?.spendable, 6)} <span>IUNA</span></h1><p class="subbalance">${formatIuna(state.balance?.confirmed, 6)} confirmed · block ${escapeHtml(state.balance?.height)}</p><div class="actions"><button class="button" data-view="send" ${readonly ? "disabled" : ""}>${icon("send")} Send</button><button class="button secondary" data-view="receive">${icon("receive")} Receive</button></div><div class="section-head"><h2>Recent activity</h2><button data-view="activity">View all</button></div><div class="panel">${activityList(5, false, state.recentTransactions)}</div></section>`; } function renderSend() { diff --git a/www/assets/iuna-ui.js b/www/assets/iuna-ui.js @@ -125,7 +125,7 @@ window.iunaApp = function iunaApp() { selectedTransferUtxos: [], selectedTransferUtxoAmounts: {}, lastSelectedTransferUtxo: null, - walletTxFilters: { transfer: true, mine: false, burn: false, reward: true }, + walletTxFilters: { transfer: true, mine: true, burn: true, reward: true }, setupPeerAddress: "iuna.jhx.app:9444", peerAddress: "", flash: null,