Skip to content

Commit f192ea7

Browse files
mohammadfawazMohammad Fawaz
authored andcommitted
add quadratic_vote example showcasing library packages
1 parent aa0597a commit f192ea7

21 files changed

Lines changed: 1675 additions & 1 deletion

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
.idea/
2-
**/README.md

quadratic_vote/README.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Quadratic Vote
2+
3+
## Summary
4+
5+
`quadratic_vote` is a governance example that demonstrates Leo **library packages**.
6+
7+
Two reusable libraries handle all the math:
8+
9+
| Package | Kind | What it provides |
10+
|---------|------|-----------------|
11+
| `sqrt_math` | library | `isqrt` — integer square root via Newton's method |
12+
| `vote_math` | library | QV weights, credit costs, voter profiles (depends on `sqrt_math`) |
13+
| `governance.aleo` | program | Private vote records, proposal outcome checks |
14+
15+
Under **Quadratic Voting (QV)**, a participant's vote weight equals ⌊√(token\_balance)⌋ and
16+
casting *k* votes costs ** credits. This makes influence grow with the square root of
17+
wealth rather than linearly — fairer to smaller holders.
18+
19+
| Token balance | Vote weight |
20+
|---------------|-------------|
21+
| 1 | 1 |
22+
| 100 | 10 |
23+
| 225 | 15 |
24+
| 1 000 | 31 |
25+
| 10 000 | 100 (cap) |
26+
27+
This example is inspired by the [Quadratic Voting](https://en.wikipedia.org/wiki/Quadratic_voting)
28+
mechanism used in decentralised governance systems such as Gitcoin Grants.
29+
30+
## Noteworthy Features
31+
32+
**Library packages**`sqrt_math` and `vote_math` are pure libraries: they compile to
33+
reusable bytecode and are never deployed to the network on their own.
34+
35+
**Library submodules** — each extra `.leo` file under `src/` becomes a named module. No
36+
declaration is needed; the filename is the module name. Items are accessed as
37+
`lib_name::module_name::item`.
38+
39+
**Cross-submodule calls within a library**`vote_math::cost::build_profile` calls
40+
`vote_math::weight::compute` internally; `sqrt_math::checks::is_perfect_square` calls
41+
`sqrt_math::newton::isqrt`.
42+
43+
**Cross-library submodule calls**`vote_math::weight::compute` reaches directly into
44+
`sqrt_math::newton::isqrt`, demonstrating the full dependency chain
45+
(`governance → vote_math::cost → vote_math::weight → sqrt_math::newton`).
46+
47+
**Top-level library constants**`vote_math::MAX_WEIGHT`, `vote_math::MIN_BALANCE`, and
48+
`sqrt_math::ISQRT_MAX` are defined in each library's `lib.leo` and referenced by name from
49+
within submodules.
50+
51+
**Library struct export**`vote_math::cost::VoterProfile` is defined in a submodule (field:
52+
`weight: u32`) and used directly as a variable type inside `governance.aleo`.
53+
54+
**Private vote receipt** — the `Vote` record is private; the token balance that drove the
55+
weight computation is never revealed on-chain.
56+
57+
## How to Build
58+
59+
### Option A — clone this repo and build in place
60+
61+
```bash
62+
cd quadratic_vote
63+
64+
cd sqrt_math && leo build && cd ..
65+
cd vote_math && leo build && cd ..
66+
cd governance && leo build && cd ..
67+
```
68+
69+
### Option B — create from scratch with the Leo CLI
70+
71+
```bash
72+
# Create the two libraries and the program.
73+
leo new --lib sqrt_math
74+
leo new --lib vote_math
75+
leo new governance
76+
77+
# Wire up dependencies.
78+
cd vote_math && leo add sqrt_math --local ../sqrt_math && cd ..
79+
cd governance && leo add sqrt_math --local ../sqrt_math && cd ..
80+
cd governance && leo add vote_math --local ../vote_math && cd ..
81+
82+
# Copy source files, then build.
83+
cd sqrt_math && leo build && cd ..
84+
cd vote_math && leo build && cd ..
85+
cd governance && leo build && cd ..
86+
```
87+
88+
`leo new --lib` creates a library package — `program.json` has no `.aleo` suffix and the
89+
source lives in `src/lib.leo` instead of `src/main.leo`. `leo add --local` records the
90+
dependency in `program.json` and lets the compiler resolve cross-package symbols.
91+
92+
## How to Run
93+
94+
All `leo run` commands are issued from inside the `governance/` directory.
95+
96+
### Cast a vote
97+
98+
A participant's token balance is kept private. The program derives their QV weight and
99+
returns a private `Vote` receipt.
100+
101+
```
102+
leo run cast_vote <proposal_id: field> <token_balance: u32> <approve: bool>
103+
```
104+
105+
**Alice (1 000 tokens, approval):**
106+
```bash
107+
leo run cast_vote 1field 1000u32 true
108+
```
109+
110+
Output:
111+
```
112+
{
113+
owner: aleo1...private,
114+
proposal_id: 1field.private,
115+
weight: 31u32.private,
116+
approve: true.private,
117+
_nonce: ...group.public
118+
}
119+
```
120+
121+
**Bob (225 tokens, rejection):**
122+
```bash
123+
leo run cast_vote 1field 225u32 false
124+
```
125+
126+
**Carol (10 000 tokens — hits the `MAX_WEIGHT` cap of 100):**
127+
```bash
128+
leo run cast_vote 1field 10000u32 true
129+
```
130+
131+
### Query the credit cost of casting votes
132+
133+
```
134+
leo run qv_cost <votes: u32>
135+
```
136+
137+
How much does it cost to cast 5 votes?
138+
139+
```bash
140+
leo run qv_cost 5u32
141+
# Output: 25u32 (= 5²)
142+
```
143+
144+
### Check whether a number is a perfect square
145+
146+
```
147+
leo run has_perfect_sqrt <token_balance: u32>
148+
```
149+
150+
This function bypasses `vote_math` entirely and calls `sqrt_math::checks::is_perfect_square`
151+
directly, illustrating that a program can reach any library submodule independently.
152+
153+
```bash
154+
leo run has_perfect_sqrt 1024u32 # 1024 = 32² → true
155+
leo run has_perfect_sqrt 1000u32 # 31² = 961, 32² = 1024 → false
156+
```
157+
158+
### Check whether a proposal is passing
159+
160+
```
161+
leo run is_passing <approvals: u32> <rejections: u32>
162+
```
163+
164+
After tallying Alice (31) + Carol (100) = 131 approvals vs Bob's 15 rejections:
165+
166+
```bash
167+
leo run is_passing 131u32 15u32
168+
# Output: true
169+
```
170+
171+
## Run the full demo
172+
173+
```bash
174+
bash run.sh
175+
```
176+
177+
## Project structure
178+
179+
Each library is split into **submodules** — separate `.leo` files under `src/` that are
180+
automatically discovered by the compiler. No explicit `module` keyword is needed; the
181+
filename becomes the module name.
182+
183+
```
184+
quadratic_vote/
185+
├── sqrt_math/ # Library: integer square root
186+
│ ├── program.json # "program": "sqrt_math" (no .aleo suffix)
187+
│ └── src/
188+
│ ├── lib.leo # const ISQRT_MAX
189+
│ ├── newton.leo # fn isqrt(n) — Newton's method [module: newton]
190+
│ └── checks.leo # fn is_perfect_square(n) [module: checks]
191+
192+
├── vote_math/ # Library: QV weight & cost formulas
193+
│ ├── program.json # depends on sqrt_math
194+
│ └── src/
195+
│ ├── lib.leo # const MAX_WEIGHT, MIN_BALANCE
196+
│ ├── weight.leo # fn compute(balance), fn is_eligible(balance) [module: weight]
197+
│ └── cost.leo # struct VoterProfile { weight }, [module: cost]
198+
│ # fn credits_for_votes, fn build_profile(balance)
199+
200+
├── governance/ # Program: private vote receipts
201+
│ ├── program.json # depends on sqrt_math + vote_math
202+
│ ├── inputs/governance.in
203+
│ ├── src/main.leo # record Vote
204+
│ │ # fn cast_vote — uses vote_math::weight + vote_math::cost
205+
│ │ # fn qv_cost — uses vote_math::cost
206+
│ │ # fn has_perfect_sqrt — uses sqrt_math::checks directly
207+
│ │ # fn is_passing
208+
│ └── tests/
209+
│ └── test_governance.leo # @test fns covering cast_vote, qv_cost, has_perfect_sqrt,
210+
│ # is_passing (18 test cases)
211+
212+
├── run.sh
213+
└── README.md
214+
```
215+
216+
### Call graph
217+
218+
```
219+
governance.aleo
220+
├── vote_math::weight::is_eligible(token_balance)
221+
│ └── vote_math::MIN_BALANCE (top-level lib constant)
222+
├── vote_math::cost::build_profile(token_balance)
223+
│ └── vote_math::weight::compute(balance) (cross-submodule call within vote_math)
224+
│ ├── sqrt_math::newton::isqrt(n) (cross-library submodule call)
225+
│ │ └── sqrt_math::ISQRT_MAX (top-level lib constant, safety assert)
226+
│ └── vote_math::MAX_WEIGHT (top-level lib constant)
227+
├── vote_math::cost::credits_for_votes(votes)
228+
└── sqrt_math::checks::is_perfect_square(n) (direct cross-library submodule call)
229+
└── sqrt_math::newton::isqrt(n) (cross-submodule call within sqrt_math)
230+
└── sqrt_math::ISQRT_MAX (top-level lib constant, safety assert)
231+
```

0 commit comments

Comments
 (0)