Skip to content

Commit cb2dcdc

Browse files
UltraDAGcomClaude Opus 4.6 (1M context)
andcommitted
Fix 6 dashboard audit issues
1. GeoIP: http:// → https:// (mixed content blocked on production) 2. PayBountyModal: resolve ULTRA IDs via /balance/ endpoint before paying — @name input now works, not just hex/bech32 addresses 3. Network switch: add event listeners to AddressPage, TxDetailPage, VertexDetailPage, RoundDetailPage, SearchResultPage — these 5 pages now refetch data when switching testnet/mainnet 4. Hardcoded #0B1120 dropdown backgrounds → var(--dag-bg) in StreamsPage, SendPage, StakingPage, PayBountyModal, Pagination (fixes light mode dropdown rendering) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8803b87 commit cb2dcdc

13 files changed

Lines changed: 93 additions & 45 deletions

File tree

dashboard/src/components/bounty/PayBountyModal.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,32 @@ export function PayBountyModal({ bounty, wallets, onClose, onSuccess }: PayBount
3939
const sats = Math.floor(parseFloat(amount) * SATS);
4040
const feeSats = Math.round(fee * SATS);
4141
if (isNaN(sats) || sats <= 0) { setError('Amount must be positive'); return; }
42-
if (!isValidAddress(hunterAddress.trim())) { setError('Invalid hunter address'); return; }
42+
43+
const input = hunterAddress.trim().replace(/^@/, '');
44+
if (!input) { setError('Hunter address is required'); return; }
4345

4446
setLoading(true);
4547
try {
48+
// Resolve ULTRA ID or address via /balance/ endpoint (accepts names, hex, bech32)
49+
let resolvedAddr = input;
50+
if (!isValidAddress(input)) {
51+
const lookupRes = await fetch(`${getNodeUrl()}/balance/${encodeURIComponent(input)}`, { signal: AbortSignal.timeout(5000) });
52+
if (!lookupRes.ok) { setError(`Could not resolve "${input}" — not a valid ULTRA ID or address`); setLoading(false); return; }
53+
const lookupData = await lookupRes.json();
54+
if (!lookupData.address) { setError(`ULTRA ID "${input}" not found`); setLoading(false); return; }
55+
resolvedAddr = lookupData.address;
56+
}
57+
const toAddr = normalizeAddress(resolvedAddr);
58+
4659
const passkey = getPasskeyInfo();
4760
if (passkey && wallet.address === passkey.address) {
4861
const balRes = await fetch(`${getNodeUrl()}/balance/${wallet.address}`, { signal: AbortSignal.timeout(5000) });
4962
const balData = await balRes.json();
50-
await signAndSubmitWithPasskey(normalizeAddress(hunterAddress.trim()), sats, feeSats, balData.nonce ?? 0, memo);
63+
await signAndSubmitWithPasskey(toAddr, sats, feeSats, balData.nonce ?? 0, memo);
5164
} else {
5265
await postTx({
5366
secret_key: wallet.secret_key,
54-
to: normalizeAddress(hunterAddress.trim()),
67+
to: toAddr,
5568
amount: sats, fee: feeSats, memo,
5669
});
5770
}
@@ -89,7 +102,7 @@ export function PayBountyModal({ bounty, wallets, onClose, onSuccess }: PayBount
89102
<div style={{ marginBottom: 12 }}>
90103
<label style={{ fontSize: 10, color: 'var(--dag-text-faint)', letterSpacing: 1, display: 'block', marginBottom: 4 }}>FROM WALLET</label>
91104
<select value={walletIdx} onChange={e => setWalletIdx(Number(e.target.value))} style={{ ...inputStyle, cursor: 'pointer' }}>
92-
{wallets.map((w, i) => <option key={i} value={i} style={{ background: '#0B1120' }}>{w.name}</option>)}
105+
{wallets.map((w, i) => <option key={i} value={i} style={{ background: 'var(--dag-bg)' }}>{w.name}</option>)}
93106
</select>
94107
</div>
95108
)}

dashboard/src/components/shared/Pagination.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export function Pagination({ page, totalPages, onPageChange, pageSize, onPageSiz
9696
style={S.select}
9797
>
9898
{[10, 25, 50].map(n => (
99-
<option key={n} value={n} style={{ background: '#0B1120' }}>{n}/page</option>
99+
<option key={n} value={n} style={{ background: 'var(--dag-bg)' }}>{n}/page</option>
100100
))}
101101
</select>
102102
)}

dashboard/src/hooks/useGeoLocatedPeers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function saveCache(cache: Map<string, GeoCache>) {
4242

4343
async function resolveGeoIP(ip: string): Promise<GeoCache | null> {
4444
try {
45-
const res = await fetch(`http://ip-api.com/json/${ip}?fields=status,lat,lon,city,country`, {
45+
const res = await fetch(`https://ip-api.com/json/${ip}?fields=status,lat,lon,city,country`, {
4646
signal: AbortSignal.timeout(4000),
4747
});
4848
if (!res.ok) return null;

dashboard/src/pages/AddressPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ export function AddressPage() {
2929
const [councilMember, setCouncilMember] = useState<string | null>(null);
3030
const [loading, setLoading] = useState(true);
3131
const [error, setError] = useState('');
32+
const [switchCount, setSwitchCount] = useState(0);
33+
34+
useEffect(() => {
35+
const handler = () => setSwitchCount(n => n + 1);
36+
window.addEventListener('ultradag-network-switch', handler);
37+
return () => window.removeEventListener('ultradag-network-switch', handler);
38+
}, []);
3239

3340
useEffect(() => {
3441
if (!address) return;
@@ -64,7 +71,7 @@ export function AddressPage() {
6471
};
6572

6673
fetchAll();
67-
}, [address]);
74+
}, [address, switchCount]);
6875

6976
if (loading) return <div className="text-slate-500 py-8 text-center">Loading address...</div>;
7077

dashboard/src/pages/RoundDetailPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ export function RoundDetailPage() {
1212
const [finalized, setFinalized] = useState(false);
1313
const [loading, setLoading] = useState(true);
1414
const [error, setError] = useState('');
15+
const [switchCount, setSwitchCount] = useState(0);
16+
17+
useEffect(() => {
18+
const handler = () => setSwitchCount(n => n + 1);
19+
window.addEventListener('ultradag-network-switch', handler);
20+
return () => window.removeEventListener('ultradag-network-switch', handler);
21+
}, []);
1522

1623
useEffect(() => {
1724
if (isNaN(round)) return;
@@ -33,7 +40,7 @@ export function RoundDetailPage() {
3340
};
3441

3542
fetchRound();
36-
}, [round]);
43+
}, [round, switchCount]);
3744

3845
if (isNaN(round)) {
3946
return <div className="text-red-400 py-8">Invalid round number</div>;

dashboard/src/pages/SearchResultPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ export function SearchResultPage() {
88
const navigate = useNavigate();
99
const [status, setStatus] = useState('Searching...');
1010
const [error, setError] = useState('');
11+
const [switchCount, setSwitchCount] = useState(0);
12+
13+
useEffect(() => {
14+
const handler = () => setSwitchCount(n => n + 1);
15+
window.addEventListener('ultradag-network-switch', handler);
16+
return () => window.removeEventListener('ultradag-network-switch', handler);
17+
}, []);
1118

1219
useEffect(() => {
1320
if (!query) return;
@@ -59,7 +66,7 @@ export function SearchResultPage() {
5966
};
6067

6168
search();
62-
}, [query, navigate]);
69+
}, [query, navigate, switchCount]);
6370

6471
return (
6572
<div className="space-y-6">

dashboard/src/pages/SendPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export function SendPage({ wallets, balances, unlocked, network }: SendPageProps
177177
backgroundRepeat: 'no-repeat', backgroundPosition: 'right 12px center',
178178
}}>
179179
{wallets.map((w, i) => (
180-
<option key={w.address} value={i} style={{ background: '#0B1120', color: 'var(--dag-text)' }}>
180+
<option key={w.address} value={i} style={{ background: 'var(--dag-bg)', color: 'var(--dag-text)' }}>
181181
{w.name}{((balances.get(w.address)?.balance ?? 0) / SATS).toFixed(2)} UDAG
182182
</option>
183183
))}

dashboard/src/pages/StakingPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ export function StakingPage() {
157157
<div>
158158
<span style={S.label}>Wallet</span>
159159
<select value={walletIdx} onChange={e => setWalletIdx(Number(e.target.value))} style={{ ...S.input, fontSize: 13, fontFamily: "'DM Sans',sans-serif" }}>
160-
{wallets.map((w, i) => <option key={i} value={i} style={{ background: '#0B1120' }}>{w.name}</option>)}
160+
{wallets.map((w, i) => <option key={i} value={i} style={{ background: 'var(--dag-bg)' }}>{w.name}</option>)}
161161
</select>
162162
</div>
163163
)}

dashboard/src/pages/StreamsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ export function StreamsPage({ wallets, network: _network }: StreamsPageProps) {
367367
<span style={S.label}>From Wallet</span>
368368
<select value={senderIdx} onChange={e => setSenderIdx(Number(e.target.value))} style={{ ...S.select, width: '100%' }}>
369369
{wallets.map((w, i) => (
370-
<option key={w.address} value={i} style={{ background: '#0B1120' }}>
370+
<option key={w.address} value={i} style={{ background: 'var(--dag-bg)' }}>
371371
{w.name || `Wallet ${i + 1}`}
372372
</option>
373373
))}

dashboard/src/pages/TxDetailPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ export function TxDetailPage() {
1111
const [tx, setTx] = useState<Record<string, unknown> | null>(null);
1212
const [loading, setLoading] = useState(true);
1313
const [error, setError] = useState('');
14+
const [switchCount, setSwitchCount] = useState(0);
15+
16+
useEffect(() => {
17+
const handler = () => setSwitchCount(n => n + 1);
18+
window.addEventListener('ultradag-network-switch', handler);
19+
return () => window.removeEventListener('ultradag-network-switch', handler);
20+
}, []);
1421

1522
useEffect(() => {
1623
if (!hash) return;
@@ -30,7 +37,7 @@ export function TxDetailPage() {
3037
};
3138

3239
fetchTx();
33-
}, [hash]);
40+
}, [hash, switchCount]);
3441

3542
if (loading) return <div className="text-slate-500 py-8 text-center">Loading transaction...</div>;
3643
if (error) {

0 commit comments

Comments
 (0)