@leofcoin/standards 0.2.6 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/exports/index.js +1 -0
- package/exports/private-voting.js +11 -105
- package/exports/public-voting.js +2 -110
- package/exports/staking.d.ts +39 -0
- package/exports/token-receiver.d.ts +2 -2
- package/exports/token-receiver.js +2 -1
- package/exports/token.d.ts +3 -0
- package/exports/token.js +13 -3
- package/exports/voting/interfaces/i-voting.d.ts +5 -0
- package/exports/voting/private-voting.d.ts +7 -25
- package/exports/voting/voting.d.ts +7 -12
- package/exports/voting-C0KVNQO3.js +112 -0
- package/exports/voting-xYjJlN2h.js +112 -0
- package/package.json +1 -1
- package/src/decorators/time.ts +1 -1
- package/src/interfaces/i-token.ts +0 -0
- package/src/lock.ts +166 -0
- package/src/staking.ts +165 -0
- package/src/token-receiver.ts +3 -3
- package/src/token.ts +17 -4
- package/src/voting/interfaces/i-voting.ts +5 -0
- package/src/voting/private-voting.ts +12 -113
- package/src/voting/voting.ts +7 -6
- package/src/voting/interfaces/i-private-voting.ts +0 -4
- package/src/voting/interfaces/i-public-voting.ts +0 -4
package/exports/index.js
CHANGED
|
@@ -1,104 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { V as Voting } from './voting-xYjJlN2h.js';
|
|
2
|
+
import './contract-creator.js';
|
|
2
3
|
|
|
3
|
-
class PrivateVoting extends
|
|
4
|
+
class PrivateVoting extends Voting {
|
|
4
5
|
#voters;
|
|
5
|
-
#votes;
|
|
6
|
-
#votingDisabled;
|
|
7
|
-
#votingDuration = 172800000;
|
|
8
6
|
constructor(state) {
|
|
9
7
|
super(state);
|
|
10
8
|
if (state) {
|
|
11
9
|
this.#voters = state.voters;
|
|
12
|
-
this.#votes = state.votes;
|
|
13
|
-
this.#votingDisabled = state.votingDisabled;
|
|
14
|
-
this.#votingDuration = state.votingDuration;
|
|
15
10
|
}
|
|
16
11
|
else {
|
|
17
12
|
this.#voters = [msg.sender];
|
|
18
13
|
}
|
|
19
14
|
}
|
|
20
|
-
get votes() {
|
|
21
|
-
return { ...this.#votes };
|
|
22
|
-
}
|
|
23
|
-
get voters() {
|
|
24
|
-
return { ...this.#voters };
|
|
25
|
-
}
|
|
26
|
-
get votingDisabled() {
|
|
27
|
-
return this.#votingDisabled;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
*/
|
|
32
15
|
get state() {
|
|
33
16
|
return {
|
|
34
17
|
...super.state,
|
|
35
|
-
voters: this.#voters
|
|
36
|
-
votes: this.#votes,
|
|
37
|
-
votingDisabled: this.#votingDisabled,
|
|
38
|
-
votingDuration: this.#votingDuration
|
|
18
|
+
voters: this.#voters
|
|
39
19
|
};
|
|
40
20
|
}
|
|
41
|
-
|
|
42
|
-
return
|
|
43
|
-
.filter(([id, vote]) => !vote.finished)
|
|
44
|
-
.map(([id, vote]) => {
|
|
45
|
-
return { ...vote, id };
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* create vote
|
|
50
|
-
* @param {string} vote
|
|
51
|
-
* @param {string} description
|
|
52
|
-
* @param {number} endTime
|
|
53
|
-
* @param {string} method function to run when agree amount is bigger
|
|
54
|
-
*/
|
|
55
|
-
createVote(title, description, endTime, method, args = []) {
|
|
56
|
-
if (!this.canVote(msg.sender))
|
|
57
|
-
throw new Error(`Not allowed to create a vote`);
|
|
58
|
-
const id = crypto.randomUUID();
|
|
59
|
-
this.#votes[id] = {
|
|
60
|
-
title,
|
|
61
|
-
description,
|
|
62
|
-
method,
|
|
63
|
-
endTime,
|
|
64
|
-
args
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
canVote(address) {
|
|
68
|
-
return this.#voters.includes(address);
|
|
69
|
-
}
|
|
70
|
-
#enoughVotes(id) {
|
|
71
|
-
return this.#voters.length - 2 <= Object.keys(this.#votes[id]).length;
|
|
72
|
-
}
|
|
73
|
-
#endVoting(voteId) {
|
|
74
|
-
let agree = Object.values(this.#votes[voteId].results).filter((result) => result === 1);
|
|
75
|
-
let disagree = Object.values(this.#votes[voteId].results).filter((result) => result === 0);
|
|
76
|
-
this.#votes[voteId].enoughVotes = this.#enoughVotes(voteId);
|
|
77
|
-
if (agree.length > disagree.length && this.#votes[voteId].enoughVotes)
|
|
78
|
-
this[this.#votes[voteId].method](...this.#votes[voteId].args);
|
|
79
|
-
this.#votes[voteId].finished = true;
|
|
80
|
-
}
|
|
81
|
-
vote(voteId, vote) {
|
|
82
|
-
vote = Number(vote);
|
|
83
|
-
if (vote !== 0 && vote !== 0.5 && vote !== 1)
|
|
84
|
-
throw new Error(`invalid vote value ${vote}`);
|
|
85
|
-
if (!this.#votes[voteId])
|
|
86
|
-
throw new Error(`Nothing found for ${voteId}`);
|
|
87
|
-
const ended = new Date().getTime() > this.#votes[voteId].endTime;
|
|
88
|
-
if (ended && !this.#votes[voteId].finished)
|
|
89
|
-
this.#endVoting(voteId);
|
|
90
|
-
if (ended)
|
|
91
|
-
throw new Error('voting already ended');
|
|
92
|
-
if (!this.canVote(msg.sender))
|
|
93
|
-
throw new Error(`Not allowed to vote`);
|
|
94
|
-
this.#votes[voteId][msg.sender] = vote;
|
|
95
|
-
if (this.#enoughVotes(voteId)) {
|
|
96
|
-
this.#endVoting(voteId);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
#disableVoting() {
|
|
100
|
-
this.#votingDisabled = true;
|
|
101
|
-
this.#voters = [];
|
|
21
|
+
_canVote() {
|
|
22
|
+
return this.#voters.includes(msg.sender);
|
|
102
23
|
}
|
|
103
24
|
#grantVotingPower(address) {
|
|
104
25
|
this.#voters.push(address);
|
|
@@ -106,37 +27,22 @@ class PrivateVoting extends ContractCreator {
|
|
|
106
27
|
#revokeVotingPower(address) {
|
|
107
28
|
this.#voters.splice(this.#voters.indexOf(address));
|
|
108
29
|
}
|
|
109
|
-
disableVoting() {
|
|
110
|
-
if (!this.canVote(msg.sender))
|
|
111
|
-
throw new Error('not a allowed');
|
|
112
|
-
if (this.#voters.length === 1)
|
|
113
|
-
this.#disableVoting();
|
|
114
|
-
else {
|
|
115
|
-
this.createVote(`disable voting`, `Warning this disables all voting features forever`, new Date().getTime() + this.#votingDuration, '#disableVoting', []);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
30
|
grantVotingPower(address, voteId) {
|
|
119
|
-
if (this.#voters.length === 1 && this.
|
|
31
|
+
if (this.#voters.length === 1 && this._canVote())
|
|
120
32
|
this.#grantVotingPower(address);
|
|
121
33
|
else {
|
|
122
|
-
this.createVote(`grant voting power to ${address}`, `Should we grant ${address} voting power?`, new Date().getTime() + this
|
|
34
|
+
this.createVote(`grant voting power to ${address}`, `Should we grant ${address} voting power?`, new Date().getTime() + this.votingDuration, '#grantVotingPower', [address]);
|
|
123
35
|
}
|
|
124
36
|
}
|
|
125
37
|
revokeVotingPower(address, voteId) {
|
|
126
|
-
if (!this.
|
|
38
|
+
if (!this._canVote())
|
|
127
39
|
throw new Error('not a allowed to vote');
|
|
128
|
-
if (this.#voters.length === 1 && address === msg.sender && !this
|
|
40
|
+
if (this.#voters.length === 1 && address === msg.sender && !this.votingDisabled)
|
|
129
41
|
throw new Error('only one voter left, disable voting before making this contract voteless');
|
|
130
42
|
if (this.#voters.length === 1)
|
|
131
43
|
this.#revokeVotingPower(address);
|
|
132
44
|
else {
|
|
133
|
-
this.createVote(`revoke voting power for ${address}`, `Should we revoke ${address} it's voting power?`, new Date().getTime() + this
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
sync() {
|
|
137
|
-
for (const vote of this.inProgress) {
|
|
138
|
-
if (vote.endTime < new Date().getTime())
|
|
139
|
-
this.#endVoting(vote.id);
|
|
45
|
+
this.createVote(`revoke voting power for ${address}`, `Should we revoke ${address} it's voting power?`, new Date().getTime() + this.votingDuration, '#revokeVotingPower', [address]);
|
|
140
46
|
}
|
|
141
47
|
}
|
|
142
48
|
}
|
package/exports/public-voting.js
CHANGED
|
@@ -1,113 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
class Voting extends ContractCreator {
|
|
4
|
-
#votes = {};
|
|
5
|
-
#votingDisabled = false;
|
|
6
|
-
#votingDuration = 172800000;
|
|
7
|
-
constructor(state) {
|
|
8
|
-
super(state);
|
|
9
|
-
if (state) {
|
|
10
|
-
this.#votes = state.votes;
|
|
11
|
-
this.#votingDisabled = state.votingDisabled;
|
|
12
|
-
this.#votingDuration = state.votingDuration;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
get votes() {
|
|
16
|
-
return { ...this.#votes };
|
|
17
|
-
}
|
|
18
|
-
get votingDuration() {
|
|
19
|
-
return this.#votingDuration;
|
|
20
|
-
}
|
|
21
|
-
get votingDisabled() {
|
|
22
|
-
return this.#votingDisabled;
|
|
23
|
-
}
|
|
24
|
-
get state() {
|
|
25
|
-
return {
|
|
26
|
-
...super.state,
|
|
27
|
-
votes: this.#votes,
|
|
28
|
-
votingDisabled: this.#votingDisabled,
|
|
29
|
-
votingDuration: this.#votingDuration
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
#canVote() {
|
|
33
|
-
// @ts-expect-error
|
|
34
|
-
return this._canVote?.();
|
|
35
|
-
}
|
|
36
|
-
#beforeVote() {
|
|
37
|
-
// @ts-expect-error
|
|
38
|
-
return this._beforeVote?.();
|
|
39
|
-
}
|
|
40
|
-
#afterVote() {
|
|
41
|
-
// @ts-expect-error
|
|
42
|
-
return this._afterVote?.();
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* create vote
|
|
46
|
-
* @param {string} vote
|
|
47
|
-
* @param {string} description
|
|
48
|
-
* @param {number} endTime
|
|
49
|
-
* @param {string} method function to run when agree amount is bigger
|
|
50
|
-
*/
|
|
51
|
-
createVote(title, description, endTime, method, args = []) {
|
|
52
|
-
if (!this.#canVote())
|
|
53
|
-
throw new Error(`Not allowed to create a vote`);
|
|
54
|
-
const id = crypto.randomUUID();
|
|
55
|
-
this.#votes[id] = {
|
|
56
|
-
title,
|
|
57
|
-
description,
|
|
58
|
-
method,
|
|
59
|
-
endTime,
|
|
60
|
-
args
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
#endVoting(voteId) {
|
|
64
|
-
let agree = Object.values(this.#votes[voteId].results).filter((result) => result === 1);
|
|
65
|
-
let disagree = Object.values(this.#votes[voteId].results).filter((result) => result === 0);
|
|
66
|
-
if (agree.length > disagree.length && this.#votes[voteId].enoughVotes)
|
|
67
|
-
this[this.#votes[voteId].method](...this.#votes[voteId].args);
|
|
68
|
-
this.#votes[voteId].finished = true;
|
|
69
|
-
}
|
|
70
|
-
async vote(voteId, vote) {
|
|
71
|
-
vote = Number(vote);
|
|
72
|
-
if (vote !== 0 && vote !== 0.5 && vote !== 1)
|
|
73
|
-
throw new Error(`invalid vote value ${vote}`);
|
|
74
|
-
if (!this.#votes[voteId])
|
|
75
|
-
throw new Error(`Nothing found for ${voteId}`);
|
|
76
|
-
const ended = new Date().getTime() > this.#votes[voteId].endTime;
|
|
77
|
-
if (ended && !this.#votes[voteId].finished)
|
|
78
|
-
this.#endVoting(voteId);
|
|
79
|
-
if (ended)
|
|
80
|
-
throw new Error('voting already ended');
|
|
81
|
-
if (!this.#canVote())
|
|
82
|
-
throw new Error(`Not allowed to vote`);
|
|
83
|
-
await this.#beforeVote();
|
|
84
|
-
this.#votes[voteId][msg.sender] = vote;
|
|
85
|
-
await this.#afterVote();
|
|
86
|
-
}
|
|
87
|
-
get votesInProgress() {
|
|
88
|
-
return Object.entries(this.#votes)
|
|
89
|
-
.filter(([id, vote]) => !vote.finished)
|
|
90
|
-
.map(([id, vote]) => {
|
|
91
|
-
return { ...vote, id };
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
#disableVoting() {
|
|
95
|
-
this.#votingDisabled = true;
|
|
96
|
-
}
|
|
97
|
-
disableVoting() {
|
|
98
|
-
if (!this.#canVote())
|
|
99
|
-
throw new Error('not a allowed');
|
|
100
|
-
else {
|
|
101
|
-
this.createVote(`disable voting`, `Warning this disables all voting features forever`, new Date().getTime() + this.#votingDuration, '#disableVoting', []);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
_sync() {
|
|
105
|
-
for (const vote of this.votesInProgress) {
|
|
106
|
-
if (vote.endTime < new Date().getTime())
|
|
107
|
-
this.#endVoting(vote.id);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
1
|
+
import { V as Voting } from './voting-xYjJlN2h.js';
|
|
2
|
+
import './contract-creator.js';
|
|
111
3
|
|
|
112
4
|
/**
|
|
113
5
|
* allows everybody that has a balance greater or equeal then/to tokenAmountToReceive to vote
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import Roles, { RolesState } from './roles.js';
|
|
2
|
+
export declare interface TokenState extends RolesState {
|
|
3
|
+
holders: BigNumberish;
|
|
4
|
+
balances: {
|
|
5
|
+
[address: address]: BigNumberish;
|
|
6
|
+
};
|
|
7
|
+
approvals: {
|
|
8
|
+
[owner: address]: {
|
|
9
|
+
[operator: address]: BigNumberish;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
totalSupply: BigNumberish;
|
|
13
|
+
}
|
|
14
|
+
export default class Token extends Roles {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(name: string, symbol: string, decimals?: number, state?: TokenState);
|
|
17
|
+
/**
|
|
18
|
+
* @return {Object} {holders, balances, ...}
|
|
19
|
+
*/
|
|
20
|
+
get state(): TokenState;
|
|
21
|
+
get totalSupply(): BigNumberish;
|
|
22
|
+
get name(): string;
|
|
23
|
+
get symbol(): string;
|
|
24
|
+
get holders(): TokenState['holders'];
|
|
25
|
+
get balances(): TokenState['balances'];
|
|
26
|
+
get approvals(): {
|
|
27
|
+
[owner: string]: {
|
|
28
|
+
[operator: string]: import("@ethersproject/bignumber").BigNumber;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
get decimals(): number;
|
|
32
|
+
mint(to: address, amount: BigNumberish): void;
|
|
33
|
+
burn(from: address, amount: BigNumberish): void;
|
|
34
|
+
balance(): any;
|
|
35
|
+
balanceOf(address: address): BigNumberish;
|
|
36
|
+
setApproval(operator: address, amount: BigNumberish): void;
|
|
37
|
+
approved(owner: address, operator: address, amount: BigNumberish): boolean;
|
|
38
|
+
transfer(from: address, to: address, amount: BigNumberish): void;
|
|
39
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IVoting } from './voting/interfaces/i-voting.js';
|
|
2
2
|
import PublicVoting, { PublicVotingState } from './voting/public-voting.js';
|
|
3
3
|
export interface TokenReceiverState extends PublicVotingState {
|
|
4
4
|
tokenToReceive: address;
|
|
@@ -6,7 +6,7 @@ export interface TokenReceiverState extends PublicVotingState {
|
|
|
6
6
|
tokenAmountToReceive: typeof BigNumber;
|
|
7
7
|
voteType: 'burn' | 'transfer';
|
|
8
8
|
}
|
|
9
|
-
export default class TokenReceiver extends PublicVoting implements
|
|
9
|
+
export default class TokenReceiver extends PublicVoting implements IVoting {
|
|
10
10
|
#private;
|
|
11
11
|
constructor(tokenToReceive: address, tokenAmountToReceive: typeof BigNumber, burns: boolean, state?: TokenReceiverState);
|
|
12
12
|
get tokenToReceive(): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import PublicVoting from './public-voting.js';
|
|
2
|
+
import './voting-xYjJlN2h.js';
|
|
2
3
|
import './contract-creator.js';
|
|
3
4
|
|
|
4
5
|
class TokenReceiver extends PublicVoting {
|
|
@@ -57,7 +58,7 @@ class TokenReceiver extends PublicVoting {
|
|
|
57
58
|
return msg.staticCall(this.tokenToReceive, 'transfer', [msg.sender, this.tokenReceiver, this.tokenAmountToReceive]);
|
|
58
59
|
}
|
|
59
60
|
async _beforeVote() {
|
|
60
|
-
|
|
61
|
+
return this.#beforeVote();
|
|
61
62
|
}
|
|
62
63
|
/**
|
|
63
64
|
* check if sender can pay
|
package/exports/token.d.ts
CHANGED
package/exports/token.js
CHANGED
|
@@ -25,6 +25,7 @@ class Token extends Roles {
|
|
|
25
25
|
#approvals = {};
|
|
26
26
|
#decimals = 18;
|
|
27
27
|
#totalSupply = BigNumber['from'](0);
|
|
28
|
+
#stakingContract;
|
|
28
29
|
// this.#privateField2 = 1
|
|
29
30
|
constructor(name, symbol, decimals = 18, state) {
|
|
30
31
|
if (!name)
|
|
@@ -37,6 +38,9 @@ class Token extends Roles {
|
|
|
37
38
|
this.#approvals = restoreApprovals(state.approvals);
|
|
38
39
|
this.#holders = BigNumber['from'](state.holders);
|
|
39
40
|
this.#totalSupply = BigNumber['from'](state.totalSupply);
|
|
41
|
+
this.#name = name;
|
|
42
|
+
this.#symbol = symbol;
|
|
43
|
+
this.#decimals = decimals;
|
|
40
44
|
}
|
|
41
45
|
else {
|
|
42
46
|
this.#name = name;
|
|
@@ -53,6 +57,9 @@ class Token extends Roles {
|
|
|
53
57
|
get state() {
|
|
54
58
|
return {
|
|
55
59
|
...super.state,
|
|
60
|
+
name: this.#name,
|
|
61
|
+
symbol: this.#symbol,
|
|
62
|
+
decimals: this.#decimals,
|
|
56
63
|
holders: this.holders,
|
|
57
64
|
balances: this.balances,
|
|
58
65
|
approvals: { ...this.#approvals },
|
|
@@ -87,10 +94,13 @@ class Token extends Roles {
|
|
|
87
94
|
this.#increaseBalance(to, amount);
|
|
88
95
|
}
|
|
89
96
|
burn(from, amount) {
|
|
90
|
-
if (!this.hasRole(msg.sender, 'BURN'))
|
|
97
|
+
if (!this.hasRole(msg.sender, 'BURN') || msg.sender !== from)
|
|
91
98
|
throw new Error('not allowed');
|
|
92
|
-
|
|
93
|
-
|
|
99
|
+
const total = this.#totalSupply.sub(amount);
|
|
100
|
+
if (total.gte(0)) {
|
|
101
|
+
this.#totalSupply = total;
|
|
102
|
+
this.#decreaseBalance(from, amount);
|
|
103
|
+
}
|
|
94
104
|
}
|
|
95
105
|
#beforeTransfer(from, to, amount) {
|
|
96
106
|
if (!this.#balances[from] || this.#balances[from] < amount)
|
|
@@ -1,33 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { ContractCreatorState } from '../contract-creator.js';
|
|
2
|
+
import { IVoting } from './interfaces/i-voting.js';
|
|
3
|
+
import { VotingState } from './types.js';
|
|
4
|
+
import Voting from './voting.js';
|
|
3
5
|
export interface PrivateVotingState extends VotingState, ContractCreatorState {
|
|
4
|
-
voters:
|
|
6
|
+
voters: address[];
|
|
5
7
|
}
|
|
6
|
-
export default class PrivateVoting extends
|
|
8
|
+
export default class PrivateVoting extends Voting implements IVoting {
|
|
7
9
|
#private;
|
|
8
10
|
constructor(state: PrivateVotingState);
|
|
9
|
-
get votes(): {
|
|
10
|
-
[x: string]: import("./types.js").Vote;
|
|
11
|
-
};
|
|
12
|
-
get voters(): any;
|
|
13
|
-
get votingDisabled(): boolean;
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
*/
|
|
17
11
|
get state(): PrivateVotingState;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* create vote
|
|
21
|
-
* @param {string} vote
|
|
22
|
-
* @param {string} description
|
|
23
|
-
* @param {number} endTime
|
|
24
|
-
* @param {string} method function to run when agree amount is bigger
|
|
25
|
-
*/
|
|
26
|
-
createVote(title: string, description: string, endTime: EpochTimeStamp, method: string, args?: any[]): void;
|
|
27
|
-
canVote(address: address): any;
|
|
28
|
-
vote(voteId: string, vote: VoteResult): void;
|
|
29
|
-
disableVoting(): void;
|
|
12
|
+
_canVote(): boolean;
|
|
30
13
|
grantVotingPower(address: address, voteId: string): void;
|
|
31
14
|
revokeVotingPower(address: address, voteId: string): void;
|
|
32
|
-
sync(): void;
|
|
33
15
|
}
|
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
import ContractCreator from '../contract-creator.js';
|
|
2
|
-
import { Vote, VoteResult } from './types.js';
|
|
1
|
+
import ContractCreator, { ContractCreatorState } from '../contract-creator.js';
|
|
2
|
+
import { Vote, VoteResult, VotingState as _VotingState } from './types.js';
|
|
3
|
+
export declare interface VotingState extends _VotingState, ContractCreatorState {
|
|
4
|
+
}
|
|
3
5
|
export default class Voting extends ContractCreator {
|
|
4
6
|
#private;
|
|
5
|
-
constructor(state:
|
|
7
|
+
constructor(state: VotingState);
|
|
6
8
|
get votes(): {
|
|
7
9
|
[x: string]: Vote;
|
|
8
10
|
};
|
|
9
11
|
get votingDuration(): number;
|
|
10
12
|
get votingDisabled(): boolean;
|
|
11
|
-
get state():
|
|
12
|
-
votes: {
|
|
13
|
-
[id: string]: Vote;
|
|
14
|
-
};
|
|
15
|
-
votingDisabled: boolean;
|
|
16
|
-
votingDuration: number;
|
|
17
|
-
contractCreator: string;
|
|
18
|
-
};
|
|
13
|
+
get state(): VotingState;
|
|
19
14
|
/**
|
|
20
15
|
* create vote
|
|
21
16
|
* @param {string} vote
|
|
@@ -39,5 +34,5 @@ export default class Voting extends ContractCreator {
|
|
|
39
34
|
enoughVotes?: boolean;
|
|
40
35
|
}[];
|
|
41
36
|
disableVoting(): void;
|
|
42
|
-
|
|
37
|
+
sync(): void;
|
|
43
38
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import ContractCreator from './contract-creator.js';
|
|
2
|
+
|
|
3
|
+
class Voting extends ContractCreator {
|
|
4
|
+
#votes = {};
|
|
5
|
+
#votingDisabled = false;
|
|
6
|
+
#votingDuration = 172800000;
|
|
7
|
+
constructor(state) {
|
|
8
|
+
super(state);
|
|
9
|
+
if (state) {
|
|
10
|
+
this.#votes = state.votes;
|
|
11
|
+
this.#votingDisabled = state.votingDisabled;
|
|
12
|
+
this.#votingDuration = state.votingDuration;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
get votes() {
|
|
16
|
+
return { ...this.#votes };
|
|
17
|
+
}
|
|
18
|
+
get votingDuration() {
|
|
19
|
+
return this.#votingDuration;
|
|
20
|
+
}
|
|
21
|
+
get votingDisabled() {
|
|
22
|
+
return this.#votingDisabled;
|
|
23
|
+
}
|
|
24
|
+
get state() {
|
|
25
|
+
return {
|
|
26
|
+
...super.state,
|
|
27
|
+
votes: this.#votes,
|
|
28
|
+
votingDisabled: this.#votingDisabled,
|
|
29
|
+
votingDuration: this.#votingDuration
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
#canVote() {
|
|
33
|
+
// @ts-expect-error
|
|
34
|
+
return this._canVote?.();
|
|
35
|
+
}
|
|
36
|
+
#beforeVote() {
|
|
37
|
+
// @ts-expect-error
|
|
38
|
+
return this._beforeVote?.();
|
|
39
|
+
}
|
|
40
|
+
#afterVote() {
|
|
41
|
+
// @ts-expect-error
|
|
42
|
+
return this._afterVote?.();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* create vote
|
|
46
|
+
* @param {string} vote
|
|
47
|
+
* @param {string} description
|
|
48
|
+
* @param {number} endTime
|
|
49
|
+
* @param {string} method function to run when agree amount is bigger
|
|
50
|
+
*/
|
|
51
|
+
createVote(title, description, endTime, method, args = []) {
|
|
52
|
+
if (!this.#canVote())
|
|
53
|
+
throw new Error(`Not allowed to create a vote`);
|
|
54
|
+
const id = crypto.randomUUID();
|
|
55
|
+
this.#votes[id] = {
|
|
56
|
+
title,
|
|
57
|
+
description,
|
|
58
|
+
method,
|
|
59
|
+
endTime,
|
|
60
|
+
args
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
#endVoting(voteId) {
|
|
64
|
+
let agree = Object.values(this.#votes[voteId].results).filter((result) => result === 1);
|
|
65
|
+
let disagree = Object.values(this.#votes[voteId].results).filter((result) => result === 0);
|
|
66
|
+
if (agree.length > disagree.length)
|
|
67
|
+
this[this.#votes[voteId].method](...this.#votes[voteId].args);
|
|
68
|
+
this.#votes[voteId].finished = true;
|
|
69
|
+
}
|
|
70
|
+
async vote(voteId, vote) {
|
|
71
|
+
vote = Number(vote);
|
|
72
|
+
if (vote !== 0 && vote !== 0.5 && vote !== 1)
|
|
73
|
+
throw new Error(`invalid vote value ${vote}`);
|
|
74
|
+
if (!this.#votes[voteId])
|
|
75
|
+
throw new Error(`Nothing found for ${voteId}`);
|
|
76
|
+
const ended = new Date().getTime() > this.#votes[voteId].endTime;
|
|
77
|
+
if (ended && !this.#votes[voteId].finished)
|
|
78
|
+
this.#endVoting(voteId);
|
|
79
|
+
if (ended)
|
|
80
|
+
throw new Error('voting already ended');
|
|
81
|
+
if (!this.#canVote())
|
|
82
|
+
throw new Error(`Not allowed to vote`);
|
|
83
|
+
await this.#beforeVote();
|
|
84
|
+
this.#votes[voteId][msg.sender] = vote;
|
|
85
|
+
await this.#afterVote();
|
|
86
|
+
}
|
|
87
|
+
get votesInProgress() {
|
|
88
|
+
return Object.entries(this.#votes)
|
|
89
|
+
.filter(([id, vote]) => !vote.finished)
|
|
90
|
+
.map(([id, vote]) => {
|
|
91
|
+
return { ...vote, id };
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
#disableVoting() {
|
|
95
|
+
this.#votingDisabled = true;
|
|
96
|
+
}
|
|
97
|
+
disableVoting() {
|
|
98
|
+
if (!this.#canVote())
|
|
99
|
+
throw new Error('not a allowed');
|
|
100
|
+
else {
|
|
101
|
+
this.createVote(`disable voting`, `Warning this disables all voting features forever`, new Date().getTime() + this.#votingDuration, '#disableVoting', []);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
_sync() {
|
|
105
|
+
for (const vote of this.votesInProgress) {
|
|
106
|
+
if (vote.endTime < new Date().getTime())
|
|
107
|
+
this.#endVoting(vote.id);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { Voting as V };
|