-
Notifications
You must be signed in to change notification settings - Fork 6
/
election.ts
278 lines (252 loc) · 8.16 KB
/
election.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
import { IQuestion } from '../metadata';
import { Census } from '../census';
import { MultiLanguage } from '../../util/lang';
import { UnpublishedElection } from './unpublished';
import { dotobject } from '../../util/common';
export interface IVoteType {
/**
* Voter can only select one answer for question
*/
uniqueChoices?: boolean;
/**
* The number of times a voter con overwrite its vote (change vote option).
*/
maxVoteOverwrites?: number;
/**
* For weighted census, the user's balance will be used as the `maxCost`. This allows splitting the voting power among
* several choices, even including quadratic voting scenarios.
*/
costFromWeight?: boolean;
/**
* Defines the `costExponent`, which is used in the computation of the total "cost" of the voted options.
* This total cost is later compared against `maxTotalCost`.
*
* The formula used to calculate the total cost is:
* totalCost = Σ (value[i] ^ costExponent) <= maxTotalCost
*
* To establish a quadratic voting election, the `costExponent` must be set to 2. As an illustration, consider a vote
* array of `[3,4]` where:
* - `3` represents the credits assigned to option 0,
* - `4` represents the credits given to option 1.
*
* The total credits spent are calculated as:
*
* ```
* 3^2 = 9 (Credits for option 0)
* 4^2 = 16 (Credits for option 1)
* Total = 25 (Total credits spent)
* ```
*
* The total credits available for spending (i.e., `maxTotalCost`) can be set in two ways during the election creation:
* - By explicitly defining the `maxTotalCost` parameter to set up same amount of credits for each voter,
* - By setting the `costFromWeight` parameter to `true` and using a weighted census. In this method, the weight
* assigned to each voter determines the credits they have available for voting.
*/
costExponent?: number;
/**
* Defines the maximum acceptable value for all fields in the voting process.
* By default, this value corresponds to the total number of choices available in a question.
*
* In the context of a quadratic voting system, this value should typically be set to 0.
*/
maxValue?: number;
/**
* Determines the maximum count or number of votes that can be cast across all fields.
* The default value corresponds to the total number of questions available in the voting process.
*
* For elections involving multiple questions (multiquestion elections), this value should be equivalent to the total
* number of questions. In contrast, for elections that don't involve multiple questions (non-multiquestion elections),
* this value should match the total number of choices available for voting.
*/
maxCount?: number;
/**
* Specifies the maximum limit on the total sum of all ballot fields' values, if applicable.
* For instance, if the vote array is `[0,0,3,2]`, the `maxTotalCost` should be set to `3`.
*
* A value of 0 implies no maximum limit or that this parameter is not applicable in the current voting context.
*/
maxTotalCost?: number;
}
export interface IElectionType {
/**
* The process can be paused and resumed.
*/
interruptible?: boolean;
/**
* Can add more voters to the census tree during the election.
*/
dynamicCensus?: boolean;
/**
* Protect the results until the end of the process if true. It will show live results otherwise.
*/
secretUntilTheEnd?: boolean;
/**
* Enable anonymous voting.
*/
anonymous?: boolean;
/**
* If the metadata has to be encrypted or not.
*/
metadata?: {
/**
* If the metadata has to be encrypted or not.
*/
encrypted?: boolean;
/**
* Password to encrypt the metadata.
*/
password?: string;
};
}
type AnyJson = boolean | number | string | null | JsonArray | JsonMap | any;
interface JsonMap {
[key: string]: AnyJson;
}
interface JsonArray extends Array<AnyJson> {}
export type CustomMeta = AnyJson | JsonArray | JsonMap;
/**
* Define election parameters.
*/
export interface IElectionParameters {
/**
* Election title
*/
title: string | MultiLanguage<string>;
/**
* Election description
*/
description?: string | MultiLanguage<string>;
/**
* Election header image url.
*/
header?: string;
/**
* Election stream Uri (ex: a video url)
*/
streamUri?: string;
/**
* Metadata (anything added by the election creator)
*/
meta?: CustomMeta;
startDate?: string | number | Date;
endDate: string | number | Date;
census: Census;
voteType?: IVoteType;
electionType?: IElectionType;
questions?: IQuestion[];
/**
* Is used to limit the number of votes that can be registered for an election. This feature helps to prevent any
* potential overflow of the blockchain when the number of votes goes beyond the maximum limit.
*
* In order to create an election, the creator is required to set the MaxCensusSize parameter to a proper value.
* Typically, this value should be equal to the size of the census. If the MaxCensusSize parameter is set to 0, an
* error will occur and the election cannot be created.
*
* If the number of votes exceeds this limit, will throw `Max census size for the election is greater than allowed
* size` error.
*/
maxCensusSize?: number;
/**
* Is used to remove the secret identities of the voters once the process is done.
*/
temporarySecretIdentity?: boolean;
/**
* Used to add the SDK version to the election metadata
*/
addSDKVersion?: boolean;
}
/**
* Represents an election
*/
export abstract class Election {
protected _title: MultiLanguage<string>;
protected _description: MultiLanguage<string>;
protected _header: string;
protected _streamUri: string;
protected _meta: CustomMeta;
protected _startDate: Date;
protected _endDate: Date;
protected _electionType: IElectionType;
protected _voteType: IVoteType;
protected _questions: IQuestion[];
protected _census: Census;
protected _maxCensusSize: number;
protected _temporarySecretIdentity: boolean;
protected _addSDKVersion: boolean;
/**
* Constructs an election
*
* @param params - Election parameters
*/
protected constructor(params?: IElectionParameters) {
if (params) {
this._title = typeof params.title === 'string' ? { default: params.title } : params.title;
this._description = typeof params.description === 'string' ? { default: params.description } : params.description;
this._header = params.header;
this._streamUri = params.streamUri;
this._meta = params.meta;
this._startDate = params.startDate ? new Date(params.startDate) : null;
this._endDate = new Date(params.endDate);
this._electionType = params.electionType;
this._voteType = params.voteType;
this._questions = params.questions ?? [];
this._census = params.census;
this._maxCensusSize = params.maxCensusSize;
this._temporarySecretIdentity = params.temporarySecretIdentity ?? false;
this._addSDKVersion = params.addSDKVersion ?? true;
}
}
/**
* Returns an unpublished election object
*
* @param params - Unpublished Election parameters
*/
public static from(params: IElectionParameters) {
return new UnpublishedElection(params);
}
get title(): MultiLanguage<string> {
return this._title;
}
get description(): MultiLanguage<string> {
return this._description;
}
get header(): string {
return this._header;
}
get streamUri(): string {
return this._streamUri;
}
get meta(): CustomMeta {
return this._meta;
}
get startDate(): Date {
return this._startDate;
}
get endDate(): Date {
return this._endDate;
}
get electionType(): IElectionType {
return this._electionType;
}
get voteType(): IVoteType {
return this._voteType;
}
get questions(): IQuestion[] {
return this._questions;
}
get census(): Census {
return this._census;
}
get maxCensusSize(): number {
return this._maxCensusSize;
}
get temporarySecretIdentity(): boolean {
return this._temporarySecretIdentity;
}
get addSDKVersion(): boolean {
return this._addSDKVersion;
}
get(dot: string) {
return this.meta ? dotobject(this.meta, dot) : null;
}
}