Last round of fixes

- Align `get_pending_delegation_events` with active delegation identity resolution: `get_node_information` + `delegation_node_identity` synthetic fallback on registry miss.
- Stop hiding pending delegation rows in `shouldHideDelegationFromList` when bonded-registry identity lookup missed.
This commit is contained in:
Tommy Verrall
2026-06-08 12:29:19 +02:00
parent 959a986e2c
commit c52fc0c9af
5 changed files with 101 additions and 52 deletions
@@ -48,13 +48,25 @@ pub async fn get_pending_delegation_events(
let mut client_specific_events = Vec::new();
for delegation_event in delegation_events {
if delegation_event.address_matches(client.nyxd.address().as_ref()) {
let node_identity = client
.nyxd
.get_mixnode_details(delegation_event.mix_id)
.await?
.mixnode_details
.map(|d| d.bond_information.mix_node.identity_key)
.unwrap_or_default();
let mut error_strings = Vec::new();
let node_identity = match get_node_information(
client,
delegation_event.mix_id,
&mut error_strings,
)
.await
{
Ok(node_details) => {
delegation_node_identity(&node_details, delegation_event.mix_id)
}
Err(err) => {
log::error!(
"Failed to resolve node identity for pending event mix_id = {}. Error: {err}",
delegation_event.mix_id
);
delegation_node_identity(&None, delegation_event.mix_id)
}
};
client_specific_events
.push(WrappedDelegationEvent::new(delegation_event, node_identity));
@@ -2,18 +2,29 @@ import React from 'react';
import { Box, Chip, Paper, Stack, Tooltip, Typography } from '@mui/material';
import { WrappedDelegationEvent } from '@nymproject/types';
import { TauriLink as Link } from 'src/components/TauriLinkWrapper';
import { formatDelegationNodeIdentityForDisplay, isUnbondedNodeIdentity } from 'src/utils/delegationIdentity';
export const PendingDelegationCard = ({ item, explorerUrl }: { item: WrappedDelegationEvent; explorerUrl: string }) => (
export const PendingDelegationCard = ({ item, explorerUrl }: { item: WrappedDelegationEvent; explorerUrl: string }) => {
const displayIdentity = formatDelegationNodeIdentityForDisplay(item.node_identity, item.event.mix_id);
const nodeIsUnbonded = isUnbondedNodeIdentity(item.node_identity);
return (
<Paper
variant="outlined"
sx={{
p: 2,
borderRadius: 3,
bgcolor: (t) => (t.palette.mode === 'dark' ? 'nym.nymWallet.nav.background' : 'nym.nymWallet.background.subtle'),
bgcolor: (t) =>
t.palette.mode === 'dark' ? 'nym.nymWallet.nav.background' : 'nym.nymWallet.background.subtle',
borderColor: 'divider',
}}
>
<Stack spacing={1.5} direction={{ xs: 'column', sm: 'row' }} alignItems={{ sm: 'center' }} flexWrap="wrap">
{nodeIsUnbonded ? (
<Typography variant="body2" color="text.secondary">
{displayIdentity}
</Typography>
) : (
<Link
target="_blank"
href={`${explorerUrl}/nodes/${item.event.mix_id}`}
@@ -21,6 +32,7 @@ export const PendingDelegationCard = ({ item, explorerUrl }: { item: WrappedDele
color="text.primary"
noIcon
/>
)}
<Typography variant="body2" color="text.secondary">
{item.event.amount?.amount} {item.event.amount?.denom?.toUpperCase() ?? 'NYM'}
</Typography>
@@ -43,4 +55,5 @@ export const PendingDelegationCard = ({ item, explorerUrl }: { item: WrappedDele
</Tooltip>
</Stack>
</Paper>
);
);
};
@@ -17,9 +17,7 @@ export function shouldHideDelegationFromList(item: DelegationListItem): boolean
}
if (isPendingDelegationItem(item)) {
if ((!item.node_identity || item.node_identity === '') && item.event && item.event.kind === 'Undelegate') {
return true;
}
// Pending rows carry mix_id on the event; do not hide when bonded-registry identity lookup missed.
return false;
}
@@ -11,6 +11,7 @@ import {
EXAMPLE_UNBONDED_MIX_ID,
buildFixedUnbondedWalletDelegation,
buildLegacyHiddenUnbondedWalletDelegation,
buildPendingUndelegateEvent,
} from './unbondedDelegation.fixture';
describe('unbonded delegation wallet visibility acceptance', () => {
@@ -55,6 +56,15 @@ describe('unbonded delegation wallet visibility acceptance', () => {
expect(searchDelegations([legacyRow], 'nonexistent-needle')).toHaveLength(0);
});
it('shows pending undelegate events when node identity lookup missed', () => {
const emptyIdentityPending = buildPendingUndelegateEvent('');
const syntheticPending = buildPendingUndelegateEvent(`unbonded:${EXAMPLE_UNBONDED_MIX_ID}`);
expect(shouldHideDelegationFromList(emptyIdentityPending)).toBe(false);
expect(shouldHideDelegationFromList(syntheticPending)).toBe(false);
expect(filterVisibleDelegations([emptyIdentityPending, syntheticPending])).toHaveLength(2);
});
it('finds the row by historical identity when the backend preserved it', () => {
const fixedRow = buildFixedUnbondedWalletDelegation({
historicalNodeIdentity: EXAMPLE_HISTORICAL_NODE_IDENTITY,
@@ -1,4 +1,4 @@
import type { DelegationWithEverything } from '@nymproject/types';
import type { DelegationWithEverything, WrappedDelegationEvent } from '@nymproject/types';
import { UNBONDED_NODE_IDENTITY_PREFIX } from './delegationIdentity';
/** Synthetic mix_id used in wallet unbonded-delegation tests. */
@@ -53,3 +53,19 @@ export function buildLegacyHiddenUnbondedWalletDelegation(
mixnode_is_unbonding: null,
};
}
export function buildPendingUndelegateEvent(
nodeIdentity: string,
mixId: number = EXAMPLE_UNBONDED_MIX_ID,
): WrappedDelegationEvent {
return {
node_identity: nodeIdentity,
event: {
kind: 'Undelegate',
mix_id: mixId,
address: EXAMPLE_DELEGATOR_ADDRESS,
amount: { amount: '1000000', denom: 'nym' },
proxy: null,
},
};
}