Skip to content

Commit ec0f050

Browse files
committed
votingpower
1 parent d85e8fa commit ec0f050

File tree

7 files changed

+264
-17
lines changed

7 files changed

+264
-17
lines changed

src/components/common/overall-layout/mobile-wrappers/wallet-data-loader-wrapper.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default function WalletDataLoaderWrapper({
4848
const setWalletAssetMetadata = useWalletsStore(
4949
(state) => state.setWalletAssetMetadata,
5050
);
51-
const { fetchProxyBalance, fetchProxyDrepInfo, setProxies } = useProxyActions();
51+
const { fetchProxyBalance, fetchProxyDrepInfo, fetchProxyDelegatorsInfo, setProxies } = useProxyActions();
5252

5353
const setDrepInfo = useWalletsStore((state) => state.setDrepInfo);
5454

@@ -205,15 +205,28 @@ export default function WalletDataLoaderWrapper({
205205
network.toString()
206206
);
207207

208-
// Fetch DRep info
208+
// Fetch DRep info with force refresh
209209
await fetchProxyDrepInfo(
210210
appWallet.id,
211211
proxy.id,
212212
proxy.proxyAddress,
213213
proxy.authTokenId,
214214
appWallet.scriptCbor,
215215
network.toString(),
216-
proxy.paramUtxo
216+
proxy.paramUtxo,
217+
true // Force refresh to bypass cache
218+
);
219+
220+
// Fetch delegators info with force refresh
221+
await fetchProxyDelegatorsInfo(
222+
appWallet.id,
223+
proxy.id,
224+
proxy.proxyAddress,
225+
proxy.authTokenId,
226+
appWallet.scriptCbor,
227+
network.toString(),
228+
proxy.paramUtxo,
229+
true // Force refresh to bypass cache
217230
);
218231

219232
} catch (error) {

src/components/common/overall-layout/proxy-data-loader.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default function ProxyDataLoader() {
1212
setProxies,
1313
fetchProxyBalance,
1414
fetchProxyDrepInfo,
15+
fetchProxyDelegatorsInfo,
1516
clearProxyData
1617
} = useProxyActions();
1718

@@ -65,6 +66,17 @@ export default function ProxyDataLoader() {
6566
appWallet.scriptCbor,
6667
network.toString(),
6768
proxy.paramUtxo,
69+
true,
70+
);
71+
await fetchProxyDelegatorsInfo(
72+
appWallet.id,
73+
proxy.id,
74+
proxy.proxyAddress,
75+
proxy.authTokenId,
76+
appWallet.scriptCbor,
77+
network.toString(),
78+
proxy.paramUtxo,
79+
true,
6880
);
6981
} catch (error) {
7082
console.error(`Error fetching data for proxy ${proxy.id}:`, error);
@@ -73,7 +85,7 @@ export default function ProxyDataLoader() {
7385
}
7486
})();
7587
}
76-
}, [proxies, appWallet?.id, appWallet?.scriptCbor, network, fetchProxyBalance, fetchProxyDrepInfo]);
88+
}, [proxies, appWallet?.id, appWallet?.scriptCbor, network, fetchProxyBalance, fetchProxyDrepInfo, fetchProxyDelegatorsInfo]);
7789

7890
// Clear proxy data when wallet changes
7991
useEffect(() => {

src/components/common/overall-layout/wallet-data-loader.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default function WalletDataLoader() {
2020
const ctx = api.useUtils();
2121
const network = useSiteStore((state) => state.network);
2222
const setRandomState = useSiteStore((state) => state.setRandomState);
23-
const { fetchProxyBalance, fetchProxyDrepInfo, setProxies } = useProxyActions();
23+
const { fetchProxyBalance, fetchProxyDrepInfo, fetchProxyDelegatorsInfo, setProxies } = useProxyActions();
2424

2525
async function fetchUtxos() {
2626
if (appWallet) {
@@ -83,15 +83,28 @@ export default function WalletDataLoader() {
8383
network.toString()
8484
);
8585

86-
// Fetch DRep info
86+
// Fetch DRep info with force refresh
8787
await fetchProxyDrepInfo(
8888
appWallet.id,
8989
proxy.id,
9090
proxy.proxyAddress,
9191
proxy.authTokenId,
9292
appWallet.scriptCbor,
9393
network.toString(),
94-
proxy.paramUtxo
94+
proxy.paramUtxo,
95+
true // Force refresh to bypass cache
96+
);
97+
98+
// Fetch delegators info with force refresh
99+
await fetchProxyDelegatorsInfo(
100+
appWallet.id,
101+
proxy.id,
102+
proxy.proxyAddress,
103+
proxy.authTokenId,
104+
appWallet.scriptCbor,
105+
network.toString(),
106+
proxy.paramUtxo,
107+
true // Force refresh to bypass cache
95108
);
96109

97110
console.log(`WalletDataLoader: Successfully fetched data for proxy ${proxy.id}`);

src/components/multisig/proxy/ProxyOverview.tsx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ interface ProxyCardProps {
4343
balance?: Array<{ unit: string; quantity: string }>;
4444
drepId?: string;
4545
drepInfo?: any;
46+
delegatorsInfo?: {
47+
delegators: Array<{ address: string; amount: string }>;
48+
totalDelegation: string;
49+
totalDelegationADA: number;
50+
count: number;
51+
};
4652
lastUpdated?: number;
4753
};
4854
isSelected: boolean;
@@ -100,6 +106,7 @@ const ProxyCard = memo(function ProxyCard({
100106
const displayBalance = proxy.balance || [];
101107
const drepId = proxy.drepId;
102108
const drepInfo = proxy.drepInfo;
109+
const delegatorsInfo = proxy.delegatorsInfo;
103110
const balanceLoading = false; // No loading state needed since data is already loaded
104111
const [isExpanded, setIsExpanded] = React.useState(false);
105112
const [isEditing, setIsEditing] = React.useState(false);
@@ -426,6 +433,64 @@ const ProxyCard = memo(function ProxyCard({
426433
</div>
427434
</div>
428435
</div>
436+
437+
{/* Delegators Information */}
438+
{delegatorsInfo && delegatorsInfo.count > 0 && (
439+
<div className="space-y-3 pt-3 border-t">
440+
<div className="flex items-center gap-2 mb-2">
441+
<Users className="h-4 w-4 text-blue-500" />
442+
<span className="text-sm font-medium">Delegations</span>
443+
</div>
444+
445+
<div className="grid grid-cols-1 gap-3">
446+
{/* Total Delegation */}
447+
<div className="space-y-2">
448+
<div className="flex items-center gap-2">
449+
<TrendingUp className="h-3 w-3 text-muted-foreground" />
450+
<span className="text-xs font-medium">Total Delegation</span>
451+
</div>
452+
<div className="p-2 bg-muted/50 rounded text-xs">
453+
<div className="font-mono">
454+
{delegatorsInfo.totalDelegationADA.toLocaleString(undefined, {
455+
minimumFractionDigits: 2,
456+
maximumFractionDigits: 6
457+
})}
458+
</div>
459+
<div className="text-muted-foreground">
460+
{delegatorsInfo.count} delegator{delegatorsInfo.count !== 1 ? 's' : ''}
461+
</div>
462+
</div>
463+
</div>
464+
465+
{/* Top Delegators */}
466+
{delegatorsInfo.delegators.length > 0 && (
467+
<div className="space-y-2">
468+
<div className="flex items-center gap-2">
469+
<Users className="h-3 w-3 text-muted-foreground" />
470+
<span className="text-xs font-medium">Top Delegators</span>
471+
</div>
472+
<div className="space-y-1 max-h-32 overflow-y-auto">
473+
{delegatorsInfo.delegators.slice(0, 5).map((delegator, index) => (
474+
<div key={delegator.address} className="flex justify-between items-center text-xs p-1 bg-muted/30 rounded">
475+
<span className="font-mono truncate flex-1 mr-2">
476+
{delegator.address.slice(0, 20)}...
477+
</span>
478+
<span className="font-mono text-muted-foreground">
479+
{(Number(delegator.amount) / 1000000).toFixed(2)}
480+
</span>
481+
</div>
482+
))}
483+
{delegatorsInfo.delegators.length > 5 && (
484+
<div className="text-xs text-muted-foreground text-center py-1">
485+
+{delegatorsInfo.delegators.length - 5} more
486+
</div>
487+
)}
488+
</div>
489+
</div>
490+
)}
491+
</div>
492+
</div>
493+
)}
429494
</div>
430495
)}
431496
</div>

src/components/multisig/proxy/offchain.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -637,12 +637,12 @@ export class MeshProxyContract extends MeshTxInitiator {
637637
return resolveScriptHashDRepId(proxyScriptHash);
638638
};
639639

640-
getDrepStatus = async () => {
640+
getDrepStatus = async (forceRefresh = false) => {
641641
const drepId = this.getDrepId();
642642

643643
// Check cache first
644644
const cached = drepStatusCache.get(drepId);
645-
if (cached && (Date.now() - cached.timestamp) < CACHE_DURATION) {
645+
if (!forceRefresh && cached && (Date.now() - cached.timestamp) < CACHE_DURATION) {
646646
return cached.data;
647647
}
648648

@@ -703,6 +703,63 @@ export class MeshProxyContract extends MeshTxInitiator {
703703
}
704704
};
705705

706+
/**
707+
* Get DRep delegators and their delegation amounts
708+
* @param forceRefresh Whether to bypass cache
709+
* @returns Array of delegators with addresses and amounts, plus total delegation
710+
*/
711+
getDrepDelegators = async (forceRefresh = false) => {
712+
const drepId = this.getDrepId();
713+
714+
// Check cache first
715+
const cacheKey = `${drepId}_delegators`;
716+
const cached = drepStatusCache.get(cacheKey);
717+
if (!forceRefresh && cached && (Date.now() - cached.timestamp) < CACHE_DURATION) {
718+
return cached.data;
719+
}
720+
721+
if (!this.mesh.fetcher) {
722+
throw new Error("Blockchain provider not found");
723+
}
724+
725+
try {
726+
const delegators = await this.mesh.fetcher.get(
727+
`/governance/dreps/${drepId}/delegators?count=100&page=1&order=asc`,
728+
);
729+
730+
// Calculate total delegation amount
731+
const totalDelegation = delegators.reduce((sum: bigint, delegator: { amount: string }) => {
732+
return sum + BigInt(delegator.amount);
733+
}, BigInt(0));
734+
735+
const result = {
736+
delegators,
737+
totalDelegation: totalDelegation.toString(),
738+
totalDelegationADA: Number(totalDelegation) / 1000000, // Convert to ADA
739+
count: delegators.length
740+
};
741+
742+
// Cache the successful result
743+
drepStatusCache.set(cacheKey, {
744+
data: result,
745+
timestamp: Date.now()
746+
});
747+
748+
return result;
749+
} catch (error: unknown) {
750+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
751+
console.log(`Failed to fetch DRep delegators: ${errorMessage}`);
752+
753+
// Return empty result for errors
754+
return {
755+
delegators: [],
756+
totalDelegation: "0",
757+
totalDelegationADA: 0,
758+
count: 0
759+
};
760+
}
761+
};
762+
706763
/**
707764
* Vote on governance proposals using proxy DRep
708765
* @param votes Array of vote objects with proposalId, voteKind, and optional metadata

src/components/pages/wallet/governance/card-info.tsx

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ export default function CardInfo({ appWallet, manualUtxos }: { appWallet: Wallet
4040
const [proxyDrepId, setProxyDrepId] = useState<string | null>(null);
4141
const [loadingProxyDrep, setLoadingProxyDrep] = useState(false);
4242
const [proxyDrepError, setProxyDrepError] = useState<string | null>(null);
43+
const [proxyDelegatorsInfo, setProxyDelegatorsInfo] = useState<{
44+
delegators: Array<{ address: string; amount: string }>;
45+
totalDelegation: string;
46+
totalDelegationADA: number;
47+
count: number;
48+
} | null>(null);
4349

4450
// Get DRep info for standard mode
4551
const currentDrepId = multisigWallet?.getKeysByRole(3) ? multisigWallet?.getDRepId() : appWallet?.dRepId;
@@ -86,8 +92,22 @@ export default function CardInfo({ appWallet, manualUtxos }: { appWallet: Wallet
8692
setProxyDrepId(drepId);
8793

8894
// Get DRep status (now with caching and proper error handling)
89-
const status = await proxyContract.getDrepStatus();
95+
const status = await proxyContract.getDrepStatus(true);
9096
setProxyDrepInfo(status);
97+
98+
// Get DRep delegators (force refresh on manual view)
99+
try {
100+
const delegators = await proxyContract.getDrepDelegators(true);
101+
setProxyDelegatorsInfo(delegators as {
102+
delegators: Array<{ address: string; amount: string }>;
103+
totalDelegation: string;
104+
totalDelegationADA: number;
105+
count: number;
106+
});
107+
} catch {
108+
// ignore, leave as null
109+
setProxyDelegatorsInfo(null);
110+
}
91111

92112
clearTimeout(timeoutId);
93113
} else {
@@ -106,6 +126,7 @@ export default function CardInfo({ appWallet, manualUtxos }: { appWallet: Wallet
106126
setProxyDrepId(null);
107127
setProxyDrepInfo(null);
108128
setProxyDrepError(null);
129+
setProxyDelegatorsInfo(null);
109130
}
110131
};
111132

@@ -382,12 +403,20 @@ export default function CardInfo({ appWallet, manualUtxos }: { appWallet: Wallet
382403
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">Voting Power</span>
383404
</div>
384405
<div className="text-2xl font-bold text-gray-900 dark:text-gray-100">
385-
{displayDrepInfo?.deposit ? `${(parseInt(displayDrepInfo.deposit) / 1000000).toFixed(2)}` :
386-
displayDrepInfo?.amount ? `${(parseInt(displayDrepInfo.amount) / 1000000).toFixed(2)}` :
387-
"0.00"} ADA
406+
{proxyDelegatorsInfo?.totalDelegationADA !== undefined
407+
? proxyDelegatorsInfo.totalDelegationADA.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 })
408+
: displayDrepInfo?.deposit
409+
? (parseInt(displayDrepInfo.deposit) / 1000000).toFixed(2)
410+
: displayDrepInfo?.amount
411+
? (parseInt(displayDrepInfo.amount) / 1000000).toFixed(2)
412+
: "0.00"} ADA
388413
</div>
389414
<div className="text-xs text-gray-500 dark:text-gray-400">
390-
{loadingProxyDrep ? "Loading..." : "Deposit amount"}
415+
{loadingProxyDrep
416+
? "Loading..."
417+
: proxyDelegatorsInfo
418+
? `${proxyDelegatorsInfo.count} delegator${proxyDelegatorsInfo.count !== 1 ? 's' : ''}`
419+
: "Deposit amount"}
391420
</div>
392421
</div>
393422
</div>

0 commit comments

Comments
 (0)