From 6fa0aa46a945753684fcef16860266358ae44225 Mon Sep 17 00:00:00 2001 From: Dorian Date: Tue, 14 Jul 2026 21:57:12 +0100 Subject: [PATCH] feat(ui): Ark wallet tab, balances, history badge + demo mocks Ark tab in Wallet Settings (status, balances, receive address, board/offboard, server config via wallet.ark-*), teal Ark badge in the transactions modal, Ark row on the home wallet card (hidden until barkd reports a balance), official bark icon, and wallet.ark-* mocks so the public demo renders the tab. Co-Authored-By: Claude Fable 5 --- neode-ui/mock-backend.js | 64 +++++ neode-ui/public/assets/img/app-icons/bark.png | Bin 0 -> 12984 bytes neode-ui/public/catalog.json | 19 ++ neode-ui/scripts/download-app-icons.js | 4 + neode-ui/src/components/TransactionsModal.vue | 5 +- .../src/components/WalletSettingsModal.vue | 227 +++++++++++++++++- neode-ui/src/views/Home.vue | 5 +- neode-ui/src/views/home/HomeWalletCard.vue | 11 +- 8 files changed, 329 insertions(+), 6 deletions(-) create mode 100644 neode-ui/public/assets/img/app-icons/bark.png diff --git a/neode-ui/mock-backend.js b/neode-ui/mock-backend.js index 75b4ae66..20dbc648 100755 --- a/neode-ui/mock-backend.js +++ b/neode-ui/mock-backend.js @@ -132,6 +132,11 @@ const SEED_WALLET = { channel_sats: 8_250_000, ecash_sats: 250_000, ecash_tokens: 12, + // Ark (barkd sidecar) demo balances — signet defaults + ark_sats: 75_000, + ark_pending_sats: 0, + ark_onchain_sats: 20_000, + ark_config: { network: 'signet', ark_server: 'https://ark.signet.2nd.dev', esplora: 'https://esplora.signet.2nd.dev' }, block_height: 892451, transactions: [ { tx_hash: 'ab12cd34ef5678901234567890abcdef12345678', amount_sats: 2_000_000, direction: 'incoming', num_confirmations: 142, block_height: 892310, time_stamp: Math.floor(Date.now()/1000) - 86400, label: 'Channel funding', total_fees: 0, dest_addresses: [] }, @@ -2209,6 +2214,63 @@ app.post('/rpc/v1', (req, res) => { const total = (mockState.federations || []).reduce((s, f) => s + (f.balance_sats || 0), 0) return res.json({ result: { balance_sats: total } }) } + case 'wallet.ark-status': { + return res.json({ + result: { + available: true, + wallet_ready: true, + wallet: { network: walletState.ark_config.network }, + ark_info: { server: walletState.ark_config.ark_server }, + config: walletState.ark_config, + }, + }) + } + case 'wallet.ark-balance': { + return res.json({ + result: { + balance_sats: walletState.ark_sats, + spendable_sats: walletState.ark_sats, + pending_sats: walletState.ark_pending_sats, + onchain_sats: walletState.ark_onchain_sats, + }, + }) + } + case 'wallet.ark-address': { + const onchain = params?.onchain === true + const address = onchain ? 'tb1q' + randomHex(16) : 'tark1' + randomHex(28) + return res.json({ result: { address, onchain } }) + } + case 'wallet.ark-board': { + const amt = params?.amount_sats ?? walletState.ark_onchain_sats + walletState.ark_onchain_sats = Math.max(0, walletState.ark_onchain_sats - amt) + walletState.ark_sats += amt + return res.json({ result: { boarded_sats: amt } }) + } + case 'wallet.ark-offboard': { + const amt = walletState.ark_sats + walletState.ark_sats = 0 + walletState.ark_onchain_sats += amt + return res.json({ result: { offboarded_sats: amt } }) + } + case 'wallet.ark-send': { + const amt = params?.amount_sats || 1000 + walletState.ark_sats = Math.max(0, walletState.ark_sats - amt) + return res.json({ result: { sent: true, movement: { id: 1, effective_balance_sat: -amt } } }) + } + case 'wallet.ark-invoice': { + return res.json({ result: { invoice: 'lntbs' + randomHex(64) } }) + } + case 'wallet.ark-history': { + return res.json({ result: { transactions: [] } }) + } + case 'wallet.ark-configure': { + const cfg = { ...walletState.ark_config } + for (const key of ['network', 'ark_server', 'esplora']) { + if (typeof params?.[key] === 'string' && params[key].trim()) cfg[key] = params[key].trim() + } + walletState.ark_config = cfg + return res.json({ result: { config: cfg } }) + } case 'content.request-onchain': { const price = params?.price_sats || 500 return res.json({ @@ -3225,6 +3287,8 @@ app.post('/rpc/v1', (req, res) => { { type: 'receive', amount_sats: 50000, timestamp: new Date(Date.now() - 86400000).toISOString(), note: 'Minted from Lightning' }, { type: 'send', amount_sats: 5000, timestamp: new Date(Date.now() - 43200000).toISOString(), note: 'Sent ecash token' }, { type: 'receive', amount_sats: 10000, timestamp: new Date(Date.now() - 3600000).toISOString(), note: 'Redeemed token' }, + // Ark movement in the unified history shape (see wallet.ark-history / load_ark_txs) + { id: 'ark-1', tx_type: 'receive', type: 'receive', amount_sats: 75000, timestamp: new Date(Date.now() - 7200000).toISOString(), description: 'Received via Ark', note: 'Received via Ark', mint_url: '', peer: '', kind: 'ark' }, ], }, }) diff --git a/neode-ui/public/assets/img/app-icons/bark.png b/neode-ui/public/assets/img/app-icons/bark.png new file mode 100644 index 0000000000000000000000000000000000000000..e9be9a0b01f1c6125125a008c815f611bf0ddabd GIT binary patch literal 12984 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 literal 0 HcmV?d00001 diff --git a/neode-ui/public/catalog.json b/neode-ui/public/catalog.json index a3c3aaa3..ca1b6a22 100644 --- a/neode-ui/public/catalog.json +++ b/neode-ui/public/catalog.json @@ -298,6 +298,25 @@ ] } }, + { + "id": "barkd", + "title": "Ark Wallet", + "version": "0.3.0", + "description": "Ark protocol wallet daemon (barkd). Lets the node hold self-custodial off-chain bitcoin via an Ark server; the wallet talks to it over a local REST API. Signet by default while Ark matures.", + "icon": "/assets/img/app-icons/bark.png", + "author": "Second", + "category": "money", + "dockerImage": "146.59.87.168:3000/lfg2025/barkd:0.3.0", + "repoUrl": "https://gitlab.com/ark-bitcoin/bark", + "containerConfig": { + "ports": [ + "3535:3535" + ], + "volumes": [ + "/var/lib/archipelago/barkd:/data" + ] + } + }, { "id": "jellyfin", "title": "Jellyfin", diff --git a/neode-ui/scripts/download-app-icons.js b/neode-ui/scripts/download-app-icons.js index 6fa5ca2f..7cbb9d12 100755 --- a/neode-ui/scripts/download-app-icons.js +++ b/neode-ui/scripts/download-app-icons.js @@ -45,6 +45,10 @@ const customIconUrls = { 'fedimint': [ 'https://raw.githubusercontent.com/fedibtc/fedimint-ui/master/apps/router/public/favicon.svg', ], + // Official bark project avatar (Ark protocol wallet daemon) + 'bark': [ + 'https://gitlab.com/uploads/-/system/project/avatar/75519706/bark-smiling-square-white-2.jpg', + ], } const iconDir = path.join(__dirname, '../public/assets/img/app-icons') diff --git a/neode-ui/src/components/TransactionsModal.vue b/neode-ui/src/components/TransactionsModal.vue index 8d174364..a2a831af 100644 --- a/neode-ui/src/components/TransactionsModal.vue +++ b/neode-ui/src/components/TransactionsModal.vue @@ -52,7 +52,7 @@ {{ kindLabel(tx) }} @@ -90,7 +90,7 @@ interface WalletTransaction { label: string block_height: number // Which rail the transaction happened on; absent = onchain (older backends) - kind?: 'onchain' | 'lightning' | 'cashu' | 'fedimint' + kind?: 'onchain' | 'lightning' | 'cashu' | 'fedimint' | 'ark' } defineProps<{ @@ -114,6 +114,7 @@ function kindLabel(tx: WalletTransaction): string { if (tx.kind === 'lightning') return '⚡ Lightning' if (tx.kind === 'cashu') return 'Cashu' if (tx.kind === 'fedimint') return 'Fedimint' + if (tx.kind === 'ark') return 'Ark' return '' } diff --git a/neode-ui/src/components/WalletSettingsModal.vue b/neode-ui/src/components/WalletSettingsModal.vue index 38f5a666..57d403fe 100644 --- a/neode-ui/src/components/WalletSettingsModal.vue +++ b/neode-ui/src/components/WalletSettingsModal.vue @@ -148,11 +148,107 @@ Joining federations lands with the Fedimint client backend.

+ + +
+
+

+ Ark holds self-custodial off-chain bitcoin via an Ark server. Funds stay recoverable on-chain even if the server disappears. +

+ Not installed + {{ arkStatus.config.network }} +
+ +
Checking Ark wallet…
+ + +
diff --git a/neode-ui/src/views/Home.vue b/neode-ui/src/views/Home.vue index fcb963c3..e06072f6 100644 --- a/neode-ui/src/views/Home.vue +++ b/neode-ui/src/views/Home.vue @@ -133,6 +133,7 @@ :wallet-lightning="walletLightning" :wallet-ecash="walletEcash" :wallet-fedimint="walletFedimint" + :wallet-ark="walletArk" :wallet-transactions="walletTransactions" :is-dev="isDev" @show-send="showSendModal = true" @@ -515,6 +516,7 @@ const showSendModal = ref(false); const showReceiveModal = ref(false); const sho async function devFaucet() { try { await rpcClient.call({ method: 'dev.faucet', params: { amount_sats: 1_000_000 } }); await loadWeb5Status() } catch { /* ignore */ } } const walletConnected = ref(false); const walletOnchain = ref(0); const walletLightning = ref(0); const walletEcash = ref(0); const walletFedimint = ref(0) +const walletArk = ref(0) const walletTransactions = ref([]) // Overlay the explorer above the current page — never navigate away. @@ -532,7 +534,7 @@ interface EcashTransaction { description: string mint_url: string peer: string - kind: 'cashu' | 'fedimint' + kind: 'cashu' | 'fedimint' | 'ark' } function ecashToWalletTransaction(tx: EcashTransaction): WalletTransaction { @@ -557,6 +559,7 @@ async function loadWeb5Status() { try { const res = await rpcClient.call<{ balance_sats: number; channel_balance_sats: number }>({ method: 'lnd.getinfo', timeout: 5000 }); walletOnchain.value = res.balance_sats || 0; walletLightning.value = res.channel_balance_sats || 0; walletConnected.value = true } catch { walletConnected.value = false } try { const res = await rpcClient.call<{ balance_sats: number }>({ method: 'wallet.ecash-balance', timeout: 5000 }); walletEcash.value = res.balance_sats ?? 0 } catch { /* keep last-known balance */ } try { const res = await rpcClient.call<{ balance_sats: number }>({ method: 'wallet.fedimint-balance', timeout: 5000 }); walletFedimint.value = res.balance_sats ?? 0 } catch { /* keep last-known balance */ } + try { const res = await rpcClient.call<{ spendable_sats: number }>({ method: 'wallet.ark-balance', timeout: 5000 }); walletArk.value = res.spendable_sats ?? 0 } catch { /* keep last-known balance */ } // Merge LND transactions with ecash/Fedimint history (wallet.ecash-history // already unifies both) — previously only LND transactions were fetched // here, so any Cashu or Fedimint receive (e.g. a TollGate payment) never diff --git a/neode-ui/src/views/home/HomeWalletCard.vue b/neode-ui/src/views/home/HomeWalletCard.vue index 94c5fcbe..2c8d174b 100644 --- a/neode-ui/src/views/home/HomeWalletCard.vue +++ b/neode-ui/src/views/home/HomeWalletCard.vue @@ -136,6 +136,14 @@ {{ walletFedimint.toLocaleString() }} sats + +
+
+ + Ark +
+ {{ (walletArk ?? 0).toLocaleString() }} sats +