17
17
18
18
如果我们希望同时考虑人们对不同问题的关注程度,又避免完全“用钱买影响力”的困局,应该怎么办呢? 这个时候就可以使用 "二次方投票" 和 "二次方资助"
19
19
20
+ ### Quadratic-Vote-Wiki
21
+
22
+ 平方投票允许投票者为额外投票“付费”,以更强烈地表达对特定议题的支持,从而导致投票结果与支付结果的最高意愿一致,而不仅仅是用户偏好的结果。无论个人偏好的强度如何。投票的支付可以通过人工或真实货币(例如,在投票成员之间平均分配代币或使用真实货币)。平方投票是基数投票类别中累积投票的变体。它与累积投票的不同之处在于将“成本”和“投票”关系从线性变为平方。
23
+
24
+ 基于市场原则,平方投票每个投票者都会事先获得了一些投票点数。他们可以使用这些点数来投票,藉以影响投票结果。如果投票者强烈支持或反对特定决定,可以花费点数,来取得额外的选票。平方投票,借此显示选民的支持、反对程度。选票价格规则决定了额外投票的成本,每多取得一次额外投票的成本会变得越来越昂贵。通过增加选民点数成本,来凸显个人对特定决定的支持。如果使用金钱,而非点数,这些花费最终会透过公共支出返回至选民身上。格伦·韦尔和 Steven Lalley 进行了相关研究,主张平方投票法的决策效率会随着选民数量的增加而增加。平方投票函数的简化公式是:
25
+
26
+ ``` math
27
+ 选民的投票成本 = (投票数)^2
28
+ ```
29
+
30
+ 智能合约中的公式稍有不同:
31
+
32
+ ``` math
33
+ 选民的投票成本 = 2^0 + 2^1 + 2^2 + ... + 2^(n-1)
34
+ ```
35
+
20
36
## 代码解读
21
37
22
38
1 . voteTool 二次方投票
26
42
27
43
两个的提案都是先通过 hash 获取到 id
28
44
29
- ```
45
+ ``` solidity
30
46
function hash(bytes memory _b) public pure returns (bytes32){
31
47
return keccak256(_b);
32
48
}
33
49
```
34
50
35
- 在实际添加或者投票的时候用的上面获取到的 id, 内部用的数字,是为了 event 可以保持该 id
36
-
37
- 实际好像 bytes32 也可以,但是 bytes/string 不行,event 中会被 hash
51
+ 由于 ` bytes ` 和 ` string ` 等动态类型作为 event 的 indexed 参数,将会被 hash,所以直接把 hash 数值作为投票的 id 值。
38
52
39
53
### 共性二
40
54
@@ -46,92 +60,107 @@ function hash(bytes memory _b) public pure returns (bytes32){
46
60
### voteTool
47
61
48
62
二次方投票, 票数越多,需要金额越多
49
- 例: 第一票 1eth,第二票 2eth, 第三票 4eth,第四票 8eth,
50
- 票数 n 金额 = 2\*\* (n-1)
63
+
64
+ 例: 第一票 1eth,第二票 2eth, 第三票 4eth,第四票 8eth...
65
+
66
+ 那么第 n 票的成本则是:
67
+
68
+ ``` math
69
+ cost to the voter = 2^(n-1)
70
+ ```
51
71
52
72
暂未兼容 eth/token 一起投
53
73
54
- - addProposal(uint256 \ _ proposal) public onlyOwner (添加提案)
55
- - expireProposal(uint256 \ _ proposal) public onlyOwner (过期后无法再投票)
56
- - vote(uint256 \ _ proposal, uint256 \ _ n) public payable(投票)
57
- - withdraw() public onlyOwner(内部只是提 eth, 代币需要修改)
74
+ - ` addProposal(uint256 _proposal) public onlyOwner ` (添加提案)
75
+ - ` expireProposal(uint256 _proposal) public onlyOwner ` (过期后无法再投票)
76
+ - ` vote(uint256 _proposal, uint256 _n) public payable ` (投票)
77
+ - ` withdraw() public onlyOwner ` (内部只是提 eth, 代币需要修改)
58
78
59
79
### financingTool
60
80
81
+ ![ quadratic_funding.png] ( https://vitalik.ca/images/qv-files/quadratic_funding.png )
82
+
61
83
每个用户针对某个提案投票都是总金额的开平方
62
- 公式解读由 ** Harry** 提供
63
84
64
- ```
65
- /**
66
- 绿色:
67
- 项目A:1*1 = 1
68
- 项目B:
69
- 用户1:4:边长2
70
- 用户2:16:边长4,总计 6
71
- 用户1:12,总计:6-2+(4+12)开根号=8
72
- 项目C:2*2=4
73
- 项目D:3*3=9
74
-
75
- 底边总长度:1+8+2+3=14
76
-
77
- 总方块面积:14*14 = 196
78
-
79
- 配捐 = 196-(1+32+4+9) = 150
80
-
81
- 最终:
82
- A:1 + 1/14 * 150 = 11.714285714
83
- B: 32 + 8/14 * 150 = 117.714285714
84
- C: 4 + 2/14 * 150 = 25.428571429
85
- D: 9 + 3/14 * 150 = 41.142857143
86
- */
87
-
88
- struct Proposal {
89
- uint256 name;//提案id
90
- uint256 amount;//获得的金额
91
- uint256 voteCount;//获得的份额
92
- address owner;
93
- address[] userAddrArr;//捐助用户地址
94
- uint8 isEnd;//0,1
95
- }
96
-
97
- struct UserVote {//每个用户每个提案会有一个实例
98
- uint256 count;//份额
99
- uint256 amount;//金额
100
- }
85
+ 1 . 每个绿色的方块代表一次捐助的金额,大正方形的面积 C 可以理解为总资助池金额,而黄色部分面积 S 可以理解为一个由外部支持的补助资金池。我们把所有绿色方块排列在大正方形的对角线上。这时,每一个贡献者投入的金额是 ` c_i ` ,那么大正方形的面积是 ` C=(sum(sqrt(c_i)))^2 ` ,补助金额 ` S=C−sum(c_i) `
86
+ 2 . 在任何时候,只要有多于一个贡献者,那么 ` C > sum(c_i) `
87
+ 3 . 如果 S 和补助资金池不完全一致,可以根据黄色的面积按比例分配
88
+ 4 . 多次小额的捐助可以导致很大的黄色面积,从而让项目赢得更多的资金配比
89
+
90
+ ``` solidity
91
+ /**
92
+ 公式解读由 Harry 提供:
93
+ 绿色:
94
+ 项目A:1*1 = 1
95
+ 项目B:
96
+ 用户1:4:边长2
97
+ 用户2:16:边长4,总计 6
98
+ 用户1:12,总计:6-2+(4+12)开根号=8
99
+ 项目C:2*2=4
100
+ 项目D:3*3=9
101
+
102
+ 底边总长度:1+8+2+3=14
103
+
104
+ 总方块面积:14*14 = 196
105
+
106
+ 配捐 = 196-(1+32+4+9) = 150
107
+
108
+ 最终:
109
+ A:1 + 1/14 * 150 = 11.714285714
110
+ B: 32 + 8/14 * 150 = 117.714285714
111
+ C: 4 + 2/14 * 150 = 25.428571429
112
+ D: 9 + 3/14 * 150 = 41.142857143
113
+ */
114
+
115
+ struct Proposal {
116
+ uint256 name;//提案id
117
+ uint256 amount;//获得的金额
118
+ uint256 voteCount;//获得的份额
119
+ address owner;
120
+ address[] userAddrArr;//捐助用户地址
121
+ uint8 isEnd;//0,1
122
+ }
123
+
124
+ struct UserVote {//每个用户每个提案会有一个实例
125
+ uint256 count;//份额
126
+ uint256 amount;//金额
127
+ }
101
128
102
129
```
103
130
104
131
场景:每个人可以对多个提案进行捐助,在一定时间内结束,结束后给一定时间用于增加配捐时间,确认完整结束后,可以由提案 owner 去领取捐助额。
105
132
106
- - addProposal(uint256 \ _ proposal) public onlyOwner(添加提案, 内部的 p.owner=msg.sender 有误, 看需求修改)
107
- - vote(uint256 \ _ proposal, uint256 \ _ inAmount) public payable(捐助)
108
- - addExtraAmount(address \ _ maker, uint256 \ _ inAmount) public payable(配捐, \ _ maker 标记谁配捐的)
109
- - withdrawProposal(uint256 \ _ proposal) public checkEnd(结束后提取捐助额)
110
- - function getResult(uint256 \ _ proposal) public view returns (uint256, uint256) (查询提案目前的捐助额/份额)
111
- - 其他就是相关查询方法, test 开头的只是测试方法
133
+ - ` addProposal(uint256 _proposal) public onlyOwner ` (添加提案, 内部的 p.owner=msg.sender 有误, 看需求修改)
134
+ - ` vote(uint256 _proposal, uint256 _inAmount) public payable ` (捐助)
135
+ - ` addExtraAmount(address _maker, uint256 _inAmount) public payable ` (配捐, _ maker 标记谁配捐的)
136
+ - ` withdrawProposal(uint256 _proposal) public checkEnd ` (结束后提取捐助额)
137
+ - ` function getResult(uint256 _proposal) public view returns (uint256, uint256) ` (查询提案目前的捐助额/份额)
138
+ - 其他就是相关查询方法, test 开头的只是测试方法
112
139
113
140
## 测试步骤
114
141
115
142
- 安装依赖
116
143
117
- ```
118
- yarn
119
- ```
144
+ ``` sh
145
+ yarn
146
+ ```
120
147
121
148
- 编译合约
122
149
123
- ```
124
- npx hardhat compile
125
- ```
150
+ ``` sh
151
+ npx hardhat compile
152
+ ```
126
153
127
154
- 执行测试脚本
128
155
129
- ```
130
- npx hardhat test
131
- ```
156
+ ``` sh
157
+ npx hardhat test
158
+ ```
132
159
133
160
## 参考资料
134
161
162
+ - [ Quadratic Payments: A Primer] ( https://vitalik.ca/general/2019/12/07/quadratic.html )
135
163
- [ 二次方投票和二次方资助] ( https://www.matataki.io/p/6113 )
136
164
- [ 视频] ( https://www.bilibili.com/video/BV1Y5411w77b/ )
137
165
- [ gitcoin] ( https://gitcoin.co/blog/gitcoin-grants-quadratic-funding-for-the-world/ )
166
+ - [ Quadratic voting-WIKI] ( https://en.wikipedia.org/wiki/Quadratic_voting )
0 commit comments