Skip to content

Commit 112cb5a

Browse files
committed
Add PBaaS chain friendly names and identity search enhancements
- Implement multichain friendly name display via RPC discovery - Add i-address search support in identity lookup - Restrict take offer primary addresses to R-addresses only - Update preallocation manager text for clarity
1 parent bdc30c3 commit 112cb5a

8 files changed

Lines changed: 118 additions & 71 deletions

File tree

src-tauri/src/rpc/chain_discovery.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,8 @@ fn apply_fallback_names(chains: &mut [ChainConfig]) {
344344
fn get_fallback_display_name(currencyidhex: &str) -> Option<&'static str> {
345345
// ONLY mainnet PBaaS chains - NO testnet chains
346346
match currencyidhex {
347-
"e9e10955b7d16031e3d6f55d9c908a038e3ae47d" => Some("VARRR"),
348-
"53fe39eea8c06bba32f1a4e20db67e5524f0309d" => Some("VDEX"),
347+
"e9e10955b7d16031e3d6f55d9c908a038e3ae47d" => Some("vARRR"),
348+
"53fe39eea8c06bba32f1a4e20db67e5524f0309d" => Some("vDEX"),
349349
"f315367528394674d45277e369629605a1c3ce9f" => Some("CHIPS"),
350350
_ => None,
351351
}

src/lib/components/BlockHeightHeader.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { invoke } from "@tauri-apps/api/core";
3-
import { connectionStore, getChainParam, type ChainConfig, type ConnectionState } from "$lib/stores/connection";
3+
import { connectionStore, getChainParam, getChainDisplayName, type ChainConfig, type ConnectionState } from "$lib/stores/connection";
44
import { onDestroy } from "svelte";
55
66
let blockHeight = $state<number | null>(null);
@@ -219,7 +219,7 @@
219219
>
220220
{#each connectionState.availableChains as chain}
221221
<option value={chain.name} class="bg-white dark:bg-verusidx-stone-dark">
222-
{chain.name.toUpperCase()} {chain.is_active ? '🟢' : '🔴'}
222+
{chain.display_name} {chain.is_active ? '🟢' : '🔴'}
223223
</option>
224224
{/each}
225225
</select>
@@ -231,7 +231,7 @@
231231
{:else}
232232
<!-- Static display when only one chain or loading -->
233233
<span class="font-medium text-verusidx-stone-dark dark:text-white">
234-
{connectionState.selectedChain?.toUpperCase() || connectionState?.current?.chainName?.toUpperCase() || 'Unknown'}
234+
{getChainDisplayName(connectionState, connectionState.selectedChain)}
235235
{#if isLoadingChains}
236236
<span class="text-xs text-verusidx-mountain-grey dark:text-verusidx-mountain-mist ml-1">(Loading chains...)</span>
237237
{/if}

src/lib/components/IdentityOfferForm.svelte

Lines changed: 71 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
let hasLoadedSourceAddresses = $state(false);
6262
let hasLoadedPrivateAddresses = $state(false);
6363
let addressLoadingError = $state<string | null>(null);
64+
let showManualPrimaryInput = $state(false);
6465
6566
// Load addresses when component mounts
6667
$effect(() => {
@@ -71,41 +72,25 @@
7172
7273
async function loadSourceAddresses() {
7374
if (isLoadingSourceAddresses || hasLoadedSourceAddresses) return;
74-
75+
7576
isLoadingSourceAddresses = true;
7677
hasLoadedSourceAddresses = false;
77-
78+
7879
try {
79-
const allAddresses = [];
80-
81-
// Get addresses by account (default account "")
80+
// Get addresses by account (default account "") - R-addresses only for primary addresses
8281
try {
8382
const addresses = await invoke('get_addresses_by_account', { account: "" });
8483
if (Array.isArray(addresses)) {
85-
allAddresses.push(...addresses);
86-
console.log('✅ Loaded addresses from default account:', addresses.length);
84+
sourceAddresses = addresses;
85+
console.log('IdentityOfferForm: Loaded', addresses.length, 'R-addresses for primary addresses');
8786
}
8887
} catch (err) {
8988
console.error('Failed to load addresses by account:', err);
89+
addressLoadingError = `Failed to load R-addresses: ${err}`;
9090
}
91-
92-
// Also get private addresses from z_list_addresses
93-
try {
94-
const privateAddressList = await invoke('z_list_addresses');
95-
if (Array.isArray(privateAddressList)) {
96-
allAddresses.push(...privateAddressList);
97-
console.log('✅ Loaded private addresses:', privateAddressList.length);
98-
}
99-
} catch (err) {
100-
console.error('Failed to load private addresses:', err);
101-
}
102-
103-
sourceAddresses = allAddresses;
91+
10492
hasLoadedSourceAddresses = true;
105-
console.log('✅ IdentityOfferForm: Loaded', allAddresses.length, 'source addresses');
106-
107-
// Do not auto-populate - let user explicitly select an address
108-
93+
10994
} catch (err) {
11095
console.error('Critical error in loadSourceAddresses:', err);
11196
addressLoadingError = `Failed to load source addresses: ${err}`;
@@ -162,6 +147,22 @@
162147
}
163148
}
164149
150+
function handlePrimaryAddressDropdownChange(event: Event) {
151+
const target = event.target as HTMLSelectElement;
152+
if (target.value === '__MANUAL__') {
153+
showManualPrimaryInput = true;
154+
localIdentityData.primaryAddresses[0] = '';
155+
} else {
156+
showManualPrimaryInput = false;
157+
localIdentityData.primaryAddresses[0] = target.value;
158+
}
159+
}
160+
161+
function switchToDropdown() {
162+
showManualPrimaryInput = false;
163+
localIdentityData.primaryAddresses[0] = '';
164+
}
165+
165166
function notifyChange() {
166167
// Pass camelCase for internal component communication (consistency with other forms)
167168
// The conversion to lowercase for RPC happens in the parent component
@@ -258,36 +259,58 @@
258259
{#each localIdentityData.primaryAddresses as _, index}
259260
<div class="flex space-x-2 mb-2">
260261
{#if index === 0}
261-
<!-- First address: dropdown from loaded addresses -->
262-
<select
263-
bind:value={localIdentityData.primaryAddresses[index]}
264-
required
265-
disabled={disabled || isLoadingSourceAddresses}
266-
class="flex-1 p-3 border border-verusidx-mountain-mist dark:border-verusidx-stone-medium rounded-lg bg-white dark:bg-verusidx-stone-dark text-verusidx-stone-dark dark:text-white disabled:opacity-50"
267-
>
268-
<option value="">
269-
{#if isLoadingSourceAddresses}
270-
Loading addresses...
271-
{:else if hasLoadedSourceAddresses && sourceAddresses.length === 0}
272-
No addresses available
273-
{:else if !hasLoadedSourceAddresses}
274-
Failed to load addresses
275-
{:else}
276-
Select address
277-
{/if}
278-
</option>
279-
{#each sourceAddresses as addr}
280-
<option value={addr}>{addr}{addr.startsWith('z') ? ' (Private)' : ' (Transparent)'}</option>
281-
{/each}
282-
</select>
262+
<!-- First address: dropdown or manual input -->
263+
{#if !showManualPrimaryInput}
264+
<select
265+
onchange={handlePrimaryAddressDropdownChange}
266+
value={localIdentityData.primaryAddresses[index]}
267+
required
268+
disabled={disabled || isLoadingSourceAddresses}
269+
class="flex-1 p-3 border border-verusidx-mountain-mist dark:border-verusidx-stone-medium rounded-lg bg-white dark:bg-verusidx-stone-dark text-verusidx-stone-dark dark:text-white disabled:opacity-50"
270+
>
271+
<option value="">
272+
{#if isLoadingSourceAddresses}
273+
Loading addresses...
274+
{:else if hasLoadedSourceAddresses && sourceAddresses.length === 0}
275+
No addresses available
276+
{:else if !hasLoadedSourceAddresses}
277+
Failed to load addresses
278+
{:else}
279+
Select primary address...
280+
{/if}
281+
</option>
282+
<option value="__MANUAL__">Input address manually</option>
283+
{#each sourceAddresses as addr}
284+
<option value={addr}>{addr}</option>
285+
{/each}
286+
</select>
287+
{:else}
288+
<div class="flex-1">
289+
<input
290+
type="text"
291+
bind:value={localIdentityData.primaryAddresses[index]}
292+
required
293+
placeholder="Enter primary address (R-address)"
294+
disabled={disabled}
295+
class="w-full p-3 border border-verusidx-mountain-mist dark:border-verusidx-stone-medium rounded-lg bg-white dark:bg-verusidx-stone-dark text-verusidx-stone-dark dark:text-white disabled:opacity-50"
296+
/>
297+
<button
298+
type="button"
299+
onclick={switchToDropdown}
300+
class="mt-1 text-xs text-verusidx-turquoise-deep hover:text-verusidx-turquoise-bright"
301+
>
302+
← Use address dropdown
303+
</button>
304+
</div>
305+
{/if}
283306
{:else}
284307
<!-- Additional addresses: manual text input -->
285-
<input
308+
<input
286309
type="text"
287310
bind:value={localIdentityData.primaryAddresses[index]}
288311
required
289312
disabled={disabled}
290-
placeholder="Enter address manually"
313+
placeholder="Enter primary address (R-address)"
291314
class="flex-1 p-3 border border-verusidx-mountain-mist dark:border-verusidx-stone-medium rounded-lg bg-white dark:bg-verusidx-stone-dark text-verusidx-stone-dark dark:text-white disabled:opacity-50"
292315
/>
293316
{/if}

src/lib/components/IdentitySearchCard.svelte

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,26 @@
1818
connectionState = state;
1919
});
2020
21+
// Detect if input is an i-address (identity address)
22+
// i-addresses start with 'i' and use base58 encoding (excludes 0, O, I, l)
23+
function isIAddress(input: string): boolean {
24+
return /^i[a-km-zA-HJ-NP-Z1-9]{33,}$/.test(input);
25+
}
26+
2127
async function handleSearch() {
2228
if (!searchQuery.trim()) {
2329
searchError = "Please enter an identity name to search";
2430
return;
2531
}
2632
27-
// Format search query - ensure it has @ suffix if not already
28-
const formattedQuery = searchQuery.trim().endsWith('@') ? searchQuery.trim() : `${searchQuery.trim()}@`;
33+
const trimmedQuery = searchQuery.trim();
34+
35+
// Format search query based on input type:
36+
// - i-addresses: pass as-is
37+
// - Friendly names: ensure @ suffix
38+
const formattedQuery = isIAddress(trimmedQuery)
39+
? trimmedQuery
40+
: (trimmedQuery.endsWith('@') ? trimmedQuery : `${trimmedQuery}@`);
2941
3042
isSearching = true;
3143
searchError = null;
@@ -34,16 +46,16 @@
3446
try {
3547
const chainParam = getChainParam(connectionState?.selectedChain);
3648
console.log("IdentitySearchCard: Searching for identity on chain:", connectionState?.selectedChain, "param:", chainParam);
37-
38-
const result = await invoke("get_identity", {
49+
50+
const result = await invoke("get_identity", {
3951
name: formattedQuery,
4052
chain: chainParam
4153
});
4254
4355
console.log("IdentitySearchCard: get_identity result:", result);
4456
searchResults = result;
4557
hasSearched = true;
46-
58+
4759
// Add to recent searches (avoid duplicates)
4860
if (!recentSearches.includes(formattedQuery)) {
4961
recentSearches = [formattedQuery, ...recentSearches.slice(0, 4)]; // Keep only 5 recent

src/lib/components/currency/PreallocationManager.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
<div class="flex-1">
8181
<label class="block text-xs text-verusidx-mountain-grey dark:text-verusidx-mountain-mist mb-1">
8282
{#if isIdControlToken}
83-
Recipient Address (ID@ or R-address)
83+
Recipient Address (ID@ or i-address)
8484
{:else}
8585
Address {index + 1}
8686
{/if}
@@ -89,7 +89,7 @@
8989
type="text"
9090
value={preallocation.address}
9191
oninput={(e) => updateAddress(index, e.target.value)}
92-
placeholder={isIdControlToken ? "alice@ or RXXXxxxXXX..." : "alice@ or RXXXxxxXXX..."}
92+
placeholder={isIdControlToken ? "alice@ or iXXXxxxXXX..." : "alice@ or iXXXxxxXXX..."}
9393
required={isIdControlToken}
9494
class="w-full p-2 text-sm border border-verusidx-mountain-mist dark:border-verusidx-stone-medium rounded-lg bg-white dark:bg-verusidx-stone-dark text-verusidx-stone-dark dark:text-white"
9595
/>
@@ -152,11 +152,11 @@
152152
{#if isIdControlToken}
153153
<p class="text-xs text-verusidx-mountain-grey dark:text-verusidx-mountain-mist">
154154
ID Control Tokens must allocate exactly 0.00000001 (1 satoshi) to a single recipient.
155-
The holder of this token gains revoke/recover authority over the currency's root identity.
155+
The holder of this token gains primary authority over the currency's namespace ID@.
156156
</p>
157157
{:else}
158158
<p class="text-xs text-verusidx-mountain-grey dark:text-verusidx-mountain-mist">
159-
Preallocations distribute currency directly to specified addresses at launch.
159+
Preallocations distribute currency directly to specified recipients at launch.
160160
For basket currencies, this lowers the reserve ratio.
161161
</p>
162162
{/if}

src/lib/stores/connection.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,24 @@ export function getChainParam(selectedChain: string | null): string | null {
4747
console.warn('getChainParam: selectedChain is null, defaulting to null (VRSC mainnet)');
4848
return null;
4949
}
50-
50+
5151
// VRSC mainnet doesn't need -chain= parameter
5252
if (selectedChain.toLowerCase() === 'vrsc') {
5353
return null;
5454
}
55-
55+
5656
// All other chains (vrsctest, varrr, vdex, etc.) need -chain=chainname
5757
return selectedChain.toLowerCase();
58+
}
59+
60+
/**
61+
* Helper function to get the display name for a chain
62+
* @param state The connection state containing available chains
63+
* @param chainName The chain name to look up
64+
* @returns The display_name from availableChains, or fallback to uppercase chainName
65+
*/
66+
export function getChainDisplayName(state: ConnectionState, chainName: string | null): string {
67+
if (!chainName) return 'Unknown';
68+
const chain = state.availableChains.find(c => c.name === chainName);
69+
return chain?.display_name || chainName.toUpperCase();
5870
}

src/routes/+page.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { invoke } from "@tauri-apps/api/core";
3-
import { connectionStore, getChainParam, type ConnectionState } from "$lib/stores/connection";
3+
import { connectionStore, getChainParam, getChainDisplayName, type ConnectionState } from "$lib/stores/connection";
44
import { goto } from "$app/navigation";
55
import ThemeToggle from "$lib/components/ThemeToggle.svelte";
66
@@ -388,7 +388,7 @@
388388
<div>
389389
<h2 class="text-2xl font-bold text-verusidx-stone-dark dark:text-white">Connected to Verus PBaaS</h2>
390390
<p class="text-verusidx-mountain-grey dark:text-verusidx-mountain-mist">
391-
{connectionState.current.chainName} - {connectionState.current.host}:{connectionState.current.port}
391+
{getChainDisplayName(connectionState, connectionState.selectedChain || connectionState.current.chainName)} - {connectionState.current.host}:{connectionState.current.port}
392392
</p>
393393
</div>
394394
<button

src/routes/dashboard/+page.svelte

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { invoke } from "@tauri-apps/api/core";
3-
import { connectionStore, getChainParam, type ConnectionState } from "$lib/stores/connection";
3+
import { connectionStore, getChainParam, getChainDisplayName, type ConnectionState } from "$lib/stores/connection";
44
import { goto } from "$app/navigation";
55
import { BlockHeightHeader, ExpandableCard } from "$lib/components";
66
import { onMount, onDestroy } from "svelte";
@@ -253,7 +253,7 @@
253253
<div>
254254
<h1 class="text-3xl font-bold text-verusidx-stone-dark dark:text-white">VerusIDX Dashboard</h1>
255255
<p class="text-verusidx-mountain-grey dark:text-verusidx-mountain-mist">
256-
Connected to {connectionState.current?.chainName}
256+
Connected to {getChainDisplayName(connectionState, connectionState.selectedChain)}
257257
({connectionState.current?.host}:{connectionState.current?.port})
258258
</p>
259259
</div>
@@ -285,7 +285,7 @@
285285
<div class="space-y-3">
286286
<div class="flex justify-between">
287287
<span class="text-verusidx-mountain-grey dark:text-verusidx-mountain-mist">Chain:</span>
288-
<span class="font-medium text-verusidx-stone-dark dark:text-white">{systemInfo?.name || connectionState.selectedChain?.toUpperCase()}</span>
288+
<span class="font-medium text-verusidx-stone-dark dark:text-white">{systemInfo?.name || getChainDisplayName(connectionState, connectionState.selectedChain)}</span>
289289
</div>
290290
<div class="flex justify-between">
291291
<span class="text-verusidx-mountain-grey dark:text-verusidx-mountain-mist">Blocks:</span>
@@ -309,7 +309,7 @@
309309
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
310310
<div class="flex justify-between">
311311
<span class="text-verusidx-mountain-grey dark:text-verusidx-mountain-mist">Chain:</span>
312-
<span class="font-medium text-verusidx-stone-dark dark:text-white">{systemInfo?.name || connectionState.selectedChain?.toUpperCase()}</span>
312+
<span class="font-medium text-verusidx-stone-dark dark:text-white">{systemInfo?.name || getChainDisplayName(connectionState, connectionState.selectedChain)}</span>
313313
</div>
314314
<div class="flex justify-between">
315315
<span class="text-verusidx-mountain-grey dark:text-verusidx-mountain-mist">Version:</span>
@@ -377,7 +377,7 @@
377377

378378
<!-- Wallet Balances Card -->
379379
{#if walletInfo}
380-
<ExpandableCard title="{systemInfo?.name || connectionState.selectedChain?.toUpperCase() || 'Wallet'} Balances" cardClass="bg-white dark:bg-verusidx-stone-dark text-verusidx-stone-dark dark:text-white" modalSize="md">
380+
<ExpandableCard title="{systemInfo?.name || getChainDisplayName(connectionState, connectionState.selectedChain) || 'Wallet'} Balances" cardClass="bg-white dark:bg-verusidx-stone-dark text-verusidx-stone-dark dark:text-white" modalSize="md">
381381
<div slot="preview">
382382
<div class="space-y-3">
383383
<div class="flex justify-between">

0 commit comments

Comments
 (0)