From 36764b31d22701cfde8ccdbe63273da970f66f92 Mon Sep 17 00:00:00 2001 From: Martin Marinov Date: Wed, 1 Jul 2026 12:42:03 +0300 Subject: [PATCH] feat(dao): split voting power into castable vs votable (exclude non-voting treasury) The votable sum (getTotalVotingPower ~9.97B) includes the Treasury's 4.5B, which is held by a contract that cannot cast a vote. The overview API now also returns castableSupplyWei (votable - Treasury - FeePool ~5.47B) and nonCastableWei, and the voting-power line shows 'X castable of Y votable (Z in the treasury, non-votable)' so the real castable power is clear. --- app/api/dao-overview/route.ts | 9 +++++++++ app/build/dao/treasury-bar.tsx | 19 +++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/api/dao-overview/route.ts b/app/api/dao-overview/route.ts index b664898..d5fdd5f 100644 --- a/app/api/dao-overview/route.ts +++ b/app/api/dao-overview/route.ts @@ -156,6 +156,12 @@ async function readLightchainOverview(pub: Pub) { rawSupplyWei != null && votableWei != null && (rawSupplyWei as bigint) > (votableWei as bigint) ? (rawSupplyWei as bigint) - (votableWei as bigint) : null; + // Castable = votable minus LCAI held by protocol contracts that can't vote + // (Treasury + FeePool). votes == balance on the precompile, so their balances + // are their (non-castable) voting power. + const nonCastableWei = treasuryWei + feePoolWei; + const castableWei = + votableWei != null && (votableWei as bigint) > nonCastableWei ? (votableWei as bigint) - nonCastableWei : null; return { treasuryWei: treasuryWei.toString(), feePoolWei: feePoolWei.toString(), @@ -164,6 +170,9 @@ async function readLightchainOverview(pub: Pub) { // The actual quorum threshold + the staked-excluded base it applies to. quorumWei: quorumWei != null ? (quorumWei as bigint).toString() : null, votableSupplyWei: votableWei != null ? (votableWei as bigint).toString() : null, + // Castable = votable minus the non-votable contract holdings (Treasury/FeePool). + castableSupplyWei: castableWei != null ? castableWei.toString() : null, + nonCastableWei: nonCastableWei.toString(), rawSupplyWei: rawSupplyWei != null ? (rawSupplyWei as bigint).toString() : null, stakeExcludedWei: stakeExcludedWei != null ? stakeExcludedWei.toString() : null, stakeExcludedFromQuorum: true as boolean, diff --git a/app/build/dao/treasury-bar.tsx b/app/build/dao/treasury-bar.tsx index 6760f42..99a315b 100644 --- a/app/build/dao/treasury-bar.tsx +++ b/app/build/dao/treasury-bar.tsx @@ -31,26 +31,37 @@ interface Overview { rawSupplyWei?: string | null; stakeExcludedWei?: string | null; holderCount?: number | null; + // Votable minus non-votable contract holdings (Treasury/FeePool) = castable. + castableSupplyWei?: string | null; + nonCastableWei?: string | null; schedule?: Schedule; error?: string; } const VOTE_SYMBOL: Record = { ethereum: "LCAIB", lightchain: "LCAI" }; -/** LightChain voting-power summary: votable sum, accounts, staked-excluded. */ +/** LightChain voting-power summary: castable vs votable, staked-excluded, accounts. */ function VotingPowerLine({ chain, data }: { chain: DaoChain; data: Overview }) { if (!data.votableSupplyWei) return null; const sym = VOTE_SYMBOL[chain]; const votable = formatLcaiWei(BigInt(data.votableSupplyWei), 0); + // Castable = votable minus the Treasury/FeePool (contracts that can't vote). + const castable = data.castableSupplyWei ? formatLcaiWei(BigInt(data.castableSupplyWei), 0) : null; + const nonCastable = data.nonCastableWei && BigInt(data.nonCastableWei) > 0n ? formatLcaiWei(BigInt(data.nonCastableWei), 0) : null; const accounts = data.holderCount != null ? `~${data.holderCount.toLocaleString()} accounts` : null; const excluded = data.stakeExcludedWei && BigInt(data.stakeExcludedWei) > 0n - ? `${formatLcaiWei(BigInt(data.stakeExcludedWei), 0)} ${sym} staked (excluded from quorum)` + ? `${formatLcaiWei(BigInt(data.stakeExcludedWei), 0)} ${sym} staked (excluded)` : null; return (

- Voting power: {votable} {sym} votable - {accounts ? <> across {accounts} : null} + Voting power:{" "} + {castable ? ( + <>{castable} {sym} castable of {votable} votable{nonCastable ? <> ({nonCastable} in the treasury, non-votable) : null} + ) : ( + <>{votable} {sym} votable + )} {excluded ? <> · {excluded} : null} + {accounts ? <> · {accounts} : null}

); }