@leofcoin/standards 0.1.8 → 0.2.1
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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/CHANGELOG.md +13 -0
- package/README.md +6 -4
- package/exports/public-voting.js +20 -14
- package/exports/token-receiver.d.ts +32 -4
- package/exports/token-receiver.js +98 -6
- package/exports/token.d.ts +6 -0
- package/exports/token.js +6 -0
- package/exports/voting/interfaces/public-voting.d.ts +4 -0
- package/exports/voting/private-voting.d.ts +6 -108
- package/exports/voting/public-voting.d.ts +26 -30
- package/exports/voting/types.d.ts +23 -0
- package/package.json +71 -65
- package/rollup.config.js +2 -2
- package/src/token-receiver.ts +142 -7
- package/src/token.ts +8 -0
- package/src/voting/interfaces/i-public-voting.ts +4 -0
- package/src/voting/private-voting.ts +3 -21
- package/src/voting/public-voting.ts +26 -40
- package/src/voting/types.ts +24 -0
- package/test/public-voting.js +6 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changesets
|
|
2
|
+
|
|
3
|
+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
+
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
+
|
|
7
|
+
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
|
|
3
|
+
"changelog": "@changesets/cli/changelog",
|
|
4
|
+
"commit": true,
|
|
5
|
+
"fixed": [],
|
|
6
|
+
"linked": [],
|
|
7
|
+
"access": "public",
|
|
8
|
+
"baseBranch": "main",
|
|
9
|
+
"updateInternalDependencies": "patch",
|
|
10
|
+
"ignore": []
|
|
11
|
+
}
|
package/CHANGELOG.md
ADDED
package/README.md
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
# standards
|
|
2
|
+
|
|
2
3
|
> Contract standards
|
|
3
4
|
|
|
4
5
|
standards used in leofcoin chain kinda like erc20's but the native coin included
|
|
5
6
|
|
|
6
7
|
## install
|
|
8
|
+
|
|
7
9
|
```sh
|
|
8
10
|
npm i @leofcoin/standards
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
## usage
|
|
14
|
+
|
|
12
15
|
```js
|
|
13
|
-
import {Token} from '@leofcoin/standards'
|
|
16
|
+
import { Token } from '@leofcoin/standards'
|
|
14
17
|
|
|
15
18
|
class myCoolToken extends Token {
|
|
16
|
-
constructor() {
|
|
17
|
-
super('myCoolToken', 'MCT', 18, state
|
|
19
|
+
constructor(state) {
|
|
20
|
+
super('myCoolToken', 'MCT', 18, state)
|
|
18
21
|
}
|
|
19
22
|
}
|
|
20
23
|
```
|
|
21
|
-
|
package/exports/public-voting.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import TokenReceiver from './token-receiver.js';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* allows everybody that has a balance greater or equeal then/to tokenAmountToReceive to vote
|
|
5
3
|
*/
|
|
6
|
-
class PublicVoting
|
|
4
|
+
class PublicVoting {
|
|
7
5
|
#votes;
|
|
8
6
|
#votingDisabled;
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
#votingDuration = 172800000;
|
|
8
|
+
constructor(state) {
|
|
11
9
|
if (state) {
|
|
12
10
|
this.#votes = state.votes;
|
|
13
11
|
this.#votingDisabled = state.votingDisabled;
|
|
@@ -16,6 +14,9 @@ class PublicVoting extends TokenReceiver {
|
|
|
16
14
|
get votes() {
|
|
17
15
|
return { ...this.#votes };
|
|
18
16
|
}
|
|
17
|
+
get votingDuration() {
|
|
18
|
+
return this.#votingDuration;
|
|
19
|
+
}
|
|
19
20
|
get votingDisabled() {
|
|
20
21
|
return this.#votingDisabled;
|
|
21
22
|
}
|
|
@@ -23,7 +24,7 @@ class PublicVoting extends TokenReceiver {
|
|
|
23
24
|
*
|
|
24
25
|
*/
|
|
25
26
|
get state() {
|
|
26
|
-
return {
|
|
27
|
+
return { votes: this.#votes, votingDisabled: this.#votingDisabled, votingDuration: this.#votingDuration };
|
|
27
28
|
}
|
|
28
29
|
get inProgress() {
|
|
29
30
|
return Object.entries(this.#votes)
|
|
@@ -40,7 +41,7 @@ class PublicVoting extends TokenReceiver {
|
|
|
40
41
|
* @param {string} method function to run when agree amount is bigger
|
|
41
42
|
*/
|
|
42
43
|
createVote(title, description, endTime, method, args = []) {
|
|
43
|
-
if (!this
|
|
44
|
+
if (!this.#canVote())
|
|
44
45
|
throw new Error(`Not allowed to create a vote`);
|
|
45
46
|
const id = crypto.randomUUID();
|
|
46
47
|
this.#votes[id] = {
|
|
@@ -51,8 +52,13 @@ class PublicVoting extends TokenReceiver {
|
|
|
51
52
|
args
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
|
-
canVote(
|
|
55
|
-
|
|
55
|
+
#canVote() {
|
|
56
|
+
// @ts-expect-error
|
|
57
|
+
return this._canVote?.();
|
|
58
|
+
}
|
|
59
|
+
#beforeVote() {
|
|
60
|
+
// @ts-expect-error
|
|
61
|
+
return this._beforeVote?.();
|
|
56
62
|
}
|
|
57
63
|
#endVoting(voteId) {
|
|
58
64
|
let agree = Object.values(this.#votes[voteId].results).filter((result) => result === 1);
|
|
@@ -72,22 +78,22 @@ class PublicVoting extends TokenReceiver {
|
|
|
72
78
|
this.#endVoting(voteId);
|
|
73
79
|
if (ended)
|
|
74
80
|
throw new Error('voting already ended');
|
|
75
|
-
if (!this
|
|
81
|
+
if (!this.#canVote())
|
|
76
82
|
throw new Error(`Not allowed to vote`);
|
|
77
|
-
await
|
|
83
|
+
await this.#beforeVote();
|
|
78
84
|
this.#votes[voteId][msg.sender] = vote;
|
|
79
85
|
}
|
|
80
86
|
#disableVoting() {
|
|
81
87
|
this.#votingDisabled = true;
|
|
82
88
|
}
|
|
83
89
|
disableVoting() {
|
|
84
|
-
if (!this
|
|
90
|
+
if (!this.#canVote())
|
|
85
91
|
throw new Error('not a allowed');
|
|
86
92
|
else {
|
|
87
|
-
this.createVote(`disable voting`, `Warning this disables all voting features forever`, new Date().getTime() +
|
|
93
|
+
this.createVote(`disable voting`, `Warning this disables all voting features forever`, new Date().getTime() + this.#votingDuration, '#disableVoting', []);
|
|
88
94
|
}
|
|
89
95
|
}
|
|
90
|
-
|
|
96
|
+
_sync() {
|
|
91
97
|
for (const vote of this.inProgress) {
|
|
92
98
|
if (vote.endTime < new Date().getTime())
|
|
93
99
|
this.#endVoting(vote.id);
|
|
@@ -1,19 +1,47 @@
|
|
|
1
|
-
|
|
1
|
+
import { IPublicVoting } from './voting/interfaces/public-voting.js';
|
|
2
|
+
import PublicVoting from './voting/public-voting.js';
|
|
3
|
+
import { VotingState } from './voting/types.js';
|
|
4
|
+
export interface TokenReceiverState extends VotingState {
|
|
2
5
|
tokenToReceive: address;
|
|
6
|
+
tokenReceiver: address;
|
|
3
7
|
tokenAmountToReceive: typeof BigNumber;
|
|
8
|
+
voteType: 'burn' | 'transfer';
|
|
4
9
|
}
|
|
5
|
-
export default class TokenReceiver {
|
|
10
|
+
export default class TokenReceiver extends PublicVoting implements IPublicVoting {
|
|
6
11
|
#private;
|
|
7
|
-
constructor(tokenToReceive: address, tokenAmountToReceive: typeof BigNumber,
|
|
12
|
+
constructor(tokenToReceive: address, tokenAmountToReceive: typeof BigNumber, burns: boolean, state?: TokenReceiverState);
|
|
8
13
|
get tokenToReceive(): string;
|
|
9
14
|
get tokenAmountToReceive(): import("@ethersproject/bignumber").BigNumber;
|
|
15
|
+
get tokenReceiver(): string;
|
|
10
16
|
get state(): {
|
|
17
|
+
tokenReceiver: string;
|
|
11
18
|
tokenToReceive: string;
|
|
12
19
|
tokenAmountToReceive: import("@ethersproject/bignumber").BigNumber;
|
|
20
|
+
voteType: "burn" | "transfer";
|
|
21
|
+
votes: {
|
|
22
|
+
[id: string]: import("./voting/types.js").Vote;
|
|
23
|
+
};
|
|
24
|
+
votingDisabled: boolean;
|
|
25
|
+
votingDuration: number;
|
|
13
26
|
};
|
|
14
27
|
/**
|
|
15
28
|
* check if sender can pay
|
|
16
29
|
* @returns {boolean} promise
|
|
17
30
|
*/
|
|
18
|
-
|
|
31
|
+
_canVote(): Promise<boolean>;
|
|
32
|
+
_beforeVote(): Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* check if sender can pay
|
|
35
|
+
* @returns {boolean} promise
|
|
36
|
+
*/
|
|
37
|
+
_payTokenToReceive(): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* check if sender can pay
|
|
40
|
+
* @returns {boolean} promise
|
|
41
|
+
*/
|
|
42
|
+
_burnTokenToReceive(): Promise<boolean>;
|
|
43
|
+
changeVoteType(type: TokenReceiverState['voteType']): Promise<void>;
|
|
44
|
+
getTokensOut(amount: typeof BigNumber, receiver: address): void;
|
|
45
|
+
changeTokenAmountToReceive(): void;
|
|
46
|
+
changeTokenToReceive(): Promise<void>;
|
|
19
47
|
}
|
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
import PublicVoting from './public-voting.js';
|
|
2
|
+
|
|
3
|
+
class TokenReceiver extends PublicVoting {
|
|
2
4
|
#tokenToReceive;
|
|
3
5
|
#tokenAmountToReceive;
|
|
4
|
-
|
|
6
|
+
#tokenReceiver;
|
|
7
|
+
#voteType = 'transfer';
|
|
8
|
+
constructor(tokenToReceive, tokenAmountToReceive, burns, state) {
|
|
9
|
+
super(state);
|
|
5
10
|
if (state) {
|
|
11
|
+
this.#tokenReceiver = state.tokenReceiver;
|
|
6
12
|
this.#tokenToReceive = state.tokenToReceive;
|
|
7
13
|
this.#tokenAmountToReceive = BigNumber['from'](state.tokenAmountToReceive);
|
|
14
|
+
this.#voteType = state.voteType;
|
|
8
15
|
}
|
|
9
16
|
else {
|
|
17
|
+
this.#tokenReceiver = msg.contract;
|
|
10
18
|
this.#tokenToReceive = tokenToReceive;
|
|
11
19
|
this.#tokenAmountToReceive = BigNumber['from'](tokenAmountToReceive);
|
|
20
|
+
if (burns)
|
|
21
|
+
this.#voteType = 'burn';
|
|
12
22
|
}
|
|
13
23
|
}
|
|
14
24
|
get tokenToReceive() {
|
|
@@ -17,19 +27,101 @@ class TokenReceiver {
|
|
|
17
27
|
get tokenAmountToReceive() {
|
|
18
28
|
return this.#tokenAmountToReceive;
|
|
19
29
|
}
|
|
30
|
+
get tokenReceiver() {
|
|
31
|
+
return this.#tokenReceiver;
|
|
32
|
+
}
|
|
20
33
|
get state() {
|
|
21
34
|
return {
|
|
35
|
+
...super.state,
|
|
36
|
+
tokenReceiver: this.#tokenReceiver,
|
|
22
37
|
tokenToReceive: this.#tokenToReceive,
|
|
23
|
-
tokenAmountToReceive: this.#tokenAmountToReceive
|
|
38
|
+
tokenAmountToReceive: this.#tokenAmountToReceive,
|
|
39
|
+
voteType: this.#voteType
|
|
24
40
|
};
|
|
25
41
|
}
|
|
42
|
+
async #canVote() {
|
|
43
|
+
const amount = (await msg.staticCall(this.#tokenToReceive, 'balanceOf', [msg.sender]));
|
|
44
|
+
return amount.gte(this.#tokenAmountToReceive);
|
|
45
|
+
}
|
|
26
46
|
/**
|
|
27
47
|
* check if sender can pay
|
|
28
48
|
* @returns {boolean} promise
|
|
29
49
|
*/
|
|
30
|
-
async
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
async _canVote() {
|
|
51
|
+
return this.#canVote();
|
|
52
|
+
}
|
|
53
|
+
async #beforeVote() {
|
|
54
|
+
if (this.#voteType === 'burn')
|
|
55
|
+
return msg.staticCall(this.tokenToReceive, 'burn', [this.tokenAmountToReceive]);
|
|
56
|
+
return msg.staticCall(this.tokenToReceive, 'transfer', [msg.sender, this.tokenReceiver, this.tokenAmountToReceive]);
|
|
57
|
+
}
|
|
58
|
+
async _beforeVote() {
|
|
59
|
+
await this.#beforeVote();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* check if sender can pay
|
|
63
|
+
* @returns {boolean} promise
|
|
64
|
+
*/
|
|
65
|
+
async _payTokenToReceive() {
|
|
66
|
+
return msg.staticCall(this.#tokenToReceive, 'transfer', [
|
|
67
|
+
msg.sender,
|
|
68
|
+
this.#tokenReceiver,
|
|
69
|
+
this.#tokenAmountToReceive
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* check if sender can pay
|
|
74
|
+
* @returns {boolean} promise
|
|
75
|
+
*/
|
|
76
|
+
async _burnTokenToReceive() {
|
|
77
|
+
return msg.staticCall(this.#tokenToReceive, 'burn', [this.#tokenAmountToReceive]);
|
|
78
|
+
}
|
|
79
|
+
#changeTokenToReceive(address) {
|
|
80
|
+
this.#tokenToReceive = address;
|
|
81
|
+
}
|
|
82
|
+
#changeTokenAmountToReceive(amount) {
|
|
83
|
+
this.#tokenAmountToReceive = amount;
|
|
84
|
+
}
|
|
85
|
+
#changeVoteType(type) {
|
|
86
|
+
this.#voteType = type;
|
|
87
|
+
}
|
|
88
|
+
#getTokensOut(amount, receiver) {
|
|
89
|
+
return msg.call(this.#tokenReceiver, 'transfer', [this.#tokenReceiver, receiver, amount]);
|
|
90
|
+
}
|
|
91
|
+
async changeVoteType(type) {
|
|
92
|
+
if (!this.#canVote())
|
|
93
|
+
throw new Error('not a allowed');
|
|
94
|
+
if (this.#voteType === 'transfer' && (await this.#balance()).gt(0))
|
|
95
|
+
throw new Error('get tokens out first or they be lost forever');
|
|
96
|
+
else {
|
|
97
|
+
this.createVote(`change the token amount to receive`, `set tokenAmountToReceive`, new Date().getTime() + this.votingDuration, '#changeVoteType', [type]);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
getTokensOut(amount, receiver) {
|
|
101
|
+
if (!this.#canVote())
|
|
102
|
+
throw new Error('not a allowed');
|
|
103
|
+
else {
|
|
104
|
+
this.createVote(`withdraw all tokens`, `withdraw all tokens to ${receiver}`, new Date().getTime() + this.votingDuration, '#getTokensOut', [amount, receiver]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
changeTokenAmountToReceive() {
|
|
108
|
+
if (!this.#canVote())
|
|
109
|
+
throw new Error('not a allowed');
|
|
110
|
+
else {
|
|
111
|
+
this.createVote(`change the token amount to receive`, `set tokenAmountToReceive`, new Date().getTime() + this.votingDuration, '#changeTokenAmountToReceive', []);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
#balance() {
|
|
115
|
+
return msg.staticCall(this.#tokenToReceive, 'balanceOf', [this.#tokenReceiver]);
|
|
116
|
+
}
|
|
117
|
+
async changeTokenToReceive() {
|
|
118
|
+
if (!this.#canVote())
|
|
119
|
+
throw new Error('not a allowed');
|
|
120
|
+
if (!(await this.#balance()).eq(0) && this.#voteType === 'transfer')
|
|
121
|
+
throw new Error('get tokens out first or they be lost forever');
|
|
122
|
+
else {
|
|
123
|
+
this.createVote(`change the token to receive`, `set tokenToReceive to a new address`, new Date().getTime() + this.votingDuration, '#changeTokenToReceive', []);
|
|
124
|
+
}
|
|
33
125
|
}
|
|
34
126
|
}
|
|
35
127
|
|
package/exports/token.d.ts
CHANGED
|
@@ -26,9 +26,15 @@ export default class Token extends Roles {
|
|
|
26
26
|
get symbol(): string;
|
|
27
27
|
get holders(): {};
|
|
28
28
|
get balances(): {};
|
|
29
|
+
get approvals(): {
|
|
30
|
+
[owner: string]: {
|
|
31
|
+
[operator: string]: import("@ethersproject/bignumber").BigNumber;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
29
34
|
get decimals(): number;
|
|
30
35
|
mint(to: address, amount: BigNumberish): void;
|
|
31
36
|
burn(from: address, amount: BigNumberish): void;
|
|
37
|
+
balance(): any;
|
|
32
38
|
balanceOf(address: address): BigNumberish;
|
|
33
39
|
setApproval(operator: address, amount: BigNumberish): void;
|
|
34
40
|
approved(owner: address, operator: address, amount: BigNumberish): boolean;
|
package/exports/token.js
CHANGED
|
@@ -73,6 +73,9 @@ class Token extends Roles {
|
|
|
73
73
|
get balances() {
|
|
74
74
|
return { ...this.#balances };
|
|
75
75
|
}
|
|
76
|
+
get approvals() {
|
|
77
|
+
return this.#approvals;
|
|
78
|
+
}
|
|
76
79
|
get decimals() {
|
|
77
80
|
return this.#decimals;
|
|
78
81
|
}
|
|
@@ -110,6 +113,9 @@ class Token extends Roles {
|
|
|
110
113
|
this.#balances[address] = this.#balances[address].sub(amount);
|
|
111
114
|
this.#updateHolders(address, previousBalance);
|
|
112
115
|
}
|
|
116
|
+
balance() {
|
|
117
|
+
return this.#balances[msg.sender];
|
|
118
|
+
}
|
|
113
119
|
balanceOf(address) {
|
|
114
120
|
return this.#balances[address];
|
|
115
121
|
}
|
|
@@ -1,116 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
method: string;
|
|
5
|
-
args: any[];
|
|
6
|
-
description: string;
|
|
7
|
-
endTime: EpochTimeStamp;
|
|
8
|
-
results?: {
|
|
9
|
-
[address: address]: VoteResult;
|
|
10
|
-
};
|
|
11
|
-
finished?: boolean;
|
|
12
|
-
enoughVotes?: boolean;
|
|
13
|
-
};
|
|
14
|
-
export type PrivateVotingState = {
|
|
15
|
-
voters: address[];
|
|
16
|
-
votes: {
|
|
17
|
-
[id: string]: Vote;
|
|
18
|
-
};
|
|
19
|
-
votingDisabled: boolean;
|
|
20
|
-
};
|
|
21
|
-
export interface VoteView extends Vote {
|
|
22
|
-
id: string;
|
|
1
|
+
import { VoteResult, VoteView, VotingState } from './types.js';
|
|
2
|
+
export interface PrivateVotingState extends VotingState {
|
|
3
|
+
voters: any;
|
|
23
4
|
}
|
|
24
5
|
export default class PrivateVoting {
|
|
25
6
|
#private;
|
|
26
7
|
constructor(state: PrivateVotingState);
|
|
27
8
|
get votes(): {
|
|
28
|
-
[x: string]: Vote;
|
|
29
|
-
};
|
|
30
|
-
get voters(): {
|
|
31
|
-
[x: number]: string;
|
|
32
|
-
length: number;
|
|
33
|
-
toString(): string;
|
|
34
|
-
toLocaleString(): string;
|
|
35
|
-
pop(): string;
|
|
36
|
-
push(...items: string[]): number;
|
|
37
|
-
concat(...items: ConcatArray<string>[]): string[];
|
|
38
|
-
concat(...items: (string | ConcatArray<string>)[]): string[];
|
|
39
|
-
join(separator?: string): string;
|
|
40
|
-
reverse(): string[];
|
|
41
|
-
shift(): string;
|
|
42
|
-
slice(start?: number, end?: number): string[];
|
|
43
|
-
sort(compareFn?: (a: string, b: string) => number): string[];
|
|
44
|
-
splice(start: number, deleteCount?: number): string[];
|
|
45
|
-
splice(start: number, deleteCount: number, ...items: string[]): string[];
|
|
46
|
-
unshift(...items: string[]): number;
|
|
47
|
-
indexOf(searchElement: string, fromIndex?: number): number;
|
|
48
|
-
lastIndexOf(searchElement: string, fromIndex?: number): number;
|
|
49
|
-
every<S extends string>(predicate: (value: string, index: number, array: string[]) => value is S, thisArg?: any): this is S[];
|
|
50
|
-
every(predicate: (value: string, index: number, array: string[]) => unknown, thisArg?: any): boolean;
|
|
51
|
-
some(predicate: (value: string, index: number, array: string[]) => unknown, thisArg?: any): boolean;
|
|
52
|
-
forEach(callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any): void;
|
|
53
|
-
map<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any): U[];
|
|
54
|
-
filter<S_1 extends string>(predicate: (value: string, index: number, array: string[]) => value is S_1, thisArg?: any): S_1[];
|
|
55
|
-
filter(predicate: (value: string, index: number, array: string[]) => unknown, thisArg?: any): string[];
|
|
56
|
-
reduce(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string;
|
|
57
|
-
reduce(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string;
|
|
58
|
-
reduce<U_1>(callbackfn: (previousValue: U_1, currentValue: string, currentIndex: number, array: string[]) => U_1, initialValue: U_1): U_1;
|
|
59
|
-
reduceRight(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string;
|
|
60
|
-
reduceRight(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string;
|
|
61
|
-
reduceRight<U_2>(callbackfn: (previousValue: U_2, currentValue: string, currentIndex: number, array: string[]) => U_2, initialValue: U_2): U_2;
|
|
62
|
-
find<S_2 extends string>(predicate: (value: string, index: number, obj: string[]) => value is S_2, thisArg?: any): S_2;
|
|
63
|
-
find(predicate: (value: string, index: number, obj: string[]) => unknown, thisArg?: any): string;
|
|
64
|
-
findIndex(predicate: (value: string, index: number, obj: string[]) => unknown, thisArg?: any): number;
|
|
65
|
-
fill(value: string, start?: number, end?: number): string[];
|
|
66
|
-
copyWithin(target: number, start: number, end?: number): string[];
|
|
67
|
-
entries(): IterableIterator<[number, string]>;
|
|
68
|
-
keys(): IterableIterator<number>;
|
|
69
|
-
values(): IterableIterator<string>;
|
|
70
|
-
includes(searchElement: string, fromIndex?: number): boolean;
|
|
71
|
-
flatMap<U_3, This = undefined>(callback: (this: This, value: string, index: number, array: string[]) => U_3 | readonly U_3[], thisArg?: This): U_3[];
|
|
72
|
-
flat<A, D extends number = 1>(this: A, depth?: D): FlatArray<A, D>[];
|
|
73
|
-
at(index: number): string;
|
|
74
|
-
[Symbol.iterator](): IterableIterator<string>;
|
|
75
|
-
[Symbol.unscopables]: {
|
|
76
|
-
[x: number]: boolean;
|
|
77
|
-
length?: boolean;
|
|
78
|
-
toString?: boolean;
|
|
79
|
-
toLocaleString?: boolean;
|
|
80
|
-
pop?: boolean;
|
|
81
|
-
push?: boolean;
|
|
82
|
-
concat?: boolean;
|
|
83
|
-
join?: boolean;
|
|
84
|
-
reverse?: boolean;
|
|
85
|
-
shift?: boolean;
|
|
86
|
-
slice?: boolean;
|
|
87
|
-
sort?: boolean;
|
|
88
|
-
splice?: boolean;
|
|
89
|
-
unshift?: boolean;
|
|
90
|
-
indexOf?: boolean;
|
|
91
|
-
lastIndexOf?: boolean;
|
|
92
|
-
every?: boolean;
|
|
93
|
-
some?: boolean;
|
|
94
|
-
forEach?: boolean;
|
|
95
|
-
map?: boolean;
|
|
96
|
-
filter?: boolean;
|
|
97
|
-
reduce?: boolean;
|
|
98
|
-
reduceRight?: boolean;
|
|
99
|
-
find?: boolean;
|
|
100
|
-
findIndex?: boolean;
|
|
101
|
-
fill?: boolean;
|
|
102
|
-
copyWithin?: boolean;
|
|
103
|
-
entries?: boolean;
|
|
104
|
-
keys?: boolean;
|
|
105
|
-
values?: boolean;
|
|
106
|
-
includes?: boolean;
|
|
107
|
-
flatMap?: boolean;
|
|
108
|
-
flat?: boolean;
|
|
109
|
-
at?: boolean;
|
|
110
|
-
[Symbol.iterator]?: boolean;
|
|
111
|
-
readonly [Symbol.unscopables]?: boolean;
|
|
112
|
-
};
|
|
9
|
+
[x: string]: import("./types.js").Vote;
|
|
113
10
|
};
|
|
11
|
+
get voters(): any;
|
|
114
12
|
get votingDisabled(): boolean;
|
|
115
13
|
/**
|
|
116
14
|
*
|
|
@@ -125,7 +23,7 @@ export default class PrivateVoting {
|
|
|
125
23
|
* @param {string} method function to run when agree amount is bigger
|
|
126
24
|
*/
|
|
127
25
|
createVote(title: string, description: string, endTime: EpochTimeStamp, method: string, args?: any[]): void;
|
|
128
|
-
canVote(address: address):
|
|
26
|
+
canVote(address: address): any;
|
|
129
27
|
vote(voteId: string, vote: VoteResult): void;
|
|
130
28
|
disableVoting(): void;
|
|
131
29
|
grantVotingPower(address: address, voteId: string): void;
|
|
@@ -1,41 +1,38 @@
|
|
|
1
|
-
import
|
|
2
|
-
export type VoteResult = 0 | 0.5 | 1;
|
|
3
|
-
export type PublicVote = {
|
|
4
|
-
title: string;
|
|
5
|
-
method: string;
|
|
6
|
-
args: any[];
|
|
7
|
-
description: string;
|
|
8
|
-
endTime: EpochTimeStamp;
|
|
9
|
-
results?: {
|
|
10
|
-
[address: address]: VoteResult;
|
|
11
|
-
};
|
|
12
|
-
finished?: boolean;
|
|
13
|
-
enoughVotes?: boolean;
|
|
14
|
-
};
|
|
15
|
-
export interface PublicVotingState extends TokenReceiverState {
|
|
16
|
-
votes: {
|
|
17
|
-
[id: string]: PublicVote;
|
|
18
|
-
};
|
|
19
|
-
votingDisabled: boolean;
|
|
20
|
-
}
|
|
21
|
-
export interface VoteView extends PublicVote {
|
|
22
|
-
id: string;
|
|
23
|
-
}
|
|
1
|
+
import { VotingState, VoteResult } from './types.js';
|
|
24
2
|
/**
|
|
25
3
|
* allows everybody that has a balance greater or equeal then/to tokenAmountToReceive to vote
|
|
26
4
|
*/
|
|
27
|
-
export default class PublicVoting
|
|
5
|
+
export default class PublicVoting {
|
|
28
6
|
#private;
|
|
29
|
-
constructor(
|
|
7
|
+
constructor(state: VotingState);
|
|
30
8
|
get votes(): {
|
|
31
|
-
[x: string]:
|
|
9
|
+
[x: string]: import("./types.js").Vote;
|
|
32
10
|
};
|
|
11
|
+
get votingDuration(): number;
|
|
33
12
|
get votingDisabled(): boolean;
|
|
34
13
|
/**
|
|
35
14
|
*
|
|
36
15
|
*/
|
|
37
|
-
get state():
|
|
38
|
-
|
|
16
|
+
get state(): {
|
|
17
|
+
votes: {
|
|
18
|
+
[id: string]: import("./types.js").Vote;
|
|
19
|
+
};
|
|
20
|
+
votingDisabled: boolean;
|
|
21
|
+
votingDuration: number;
|
|
22
|
+
};
|
|
23
|
+
get inProgress(): {
|
|
24
|
+
id: string;
|
|
25
|
+
title: string;
|
|
26
|
+
method: string;
|
|
27
|
+
args: any[];
|
|
28
|
+
description: string;
|
|
29
|
+
endTime: number;
|
|
30
|
+
results?: {
|
|
31
|
+
[address: string]: VoteResult;
|
|
32
|
+
};
|
|
33
|
+
finished?: boolean;
|
|
34
|
+
enoughVotes?: boolean;
|
|
35
|
+
}[];
|
|
39
36
|
/**
|
|
40
37
|
* create vote
|
|
41
38
|
* @param {string} vote
|
|
@@ -44,8 +41,7 @@ export default class PublicVoting extends TokenReceiver {
|
|
|
44
41
|
* @param {string} method function to run when agree amount is bigger
|
|
45
42
|
*/
|
|
46
43
|
createVote(title: string, description: string, endTime: EpochTimeStamp, method: string, args?: any[]): void;
|
|
47
|
-
canVote(address: address): Promise<boolean>;
|
|
48
44
|
vote(voteId: string, vote: VoteResult): Promise<void>;
|
|
49
45
|
disableVoting(): void;
|
|
50
|
-
|
|
46
|
+
_sync(): void;
|
|
51
47
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type VoteResult = 0 | 0.5 | 1;
|
|
2
|
+
export type Vote = {
|
|
3
|
+
title: string;
|
|
4
|
+
method: string;
|
|
5
|
+
args: any[];
|
|
6
|
+
description: string;
|
|
7
|
+
endTime: EpochTimeStamp;
|
|
8
|
+
results?: {
|
|
9
|
+
[address: string]: VoteResult;
|
|
10
|
+
};
|
|
11
|
+
finished?: boolean;
|
|
12
|
+
enoughVotes?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export interface VotingState {
|
|
15
|
+
votes: {
|
|
16
|
+
[id: string]: Vote;
|
|
17
|
+
};
|
|
18
|
+
votingDisabled: boolean;
|
|
19
|
+
votingDuration: number;
|
|
20
|
+
}
|
|
21
|
+
export interface VoteView extends Vote {
|
|
22
|
+
id: string;
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -1,65 +1,71 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@leofcoin/standards",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "Contract standards",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"exports": {
|
|
7
|
-
".": {
|
|
8
|
-
"import": "./exports/index.js",
|
|
9
|
-
"types": "./exports/index.d.ts"
|
|
10
|
-
},
|
|
11
|
-
"./token": {
|
|
12
|
-
"import": "./exports/token.js",
|
|
13
|
-
"types": "./exports/token.d.ts"
|
|
14
|
-
},
|
|
15
|
-
"./roles": {
|
|
16
|
-
"import": "./exports/roles.js",
|
|
17
|
-
"types": "./exports/roles.d.ts"
|
|
18
|
-
},
|
|
19
|
-
"./public-voting": {
|
|
20
|
-
"import": "./exports/public-voting.js",
|
|
21
|
-
"types": "./exports/public-voting.d.ts"
|
|
22
|
-
},
|
|
23
|
-
"./private-voting": {
|
|
24
|
-
"import": "./exports/private-voting.js",
|
|
25
|
-
"types": "./exports/private-voting.d.ts"
|
|
26
|
-
},
|
|
27
|
-
"./token-receiver": {
|
|
28
|
-
"import": "./exports/token-receiver.js",
|
|
29
|
-
"types": "./exports/token-receiver.d.ts"
|
|
30
|
-
},
|
|
31
|
-
"./
|
|
32
|
-
"import": "./exports/
|
|
33
|
-
"types": "./exports/
|
|
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
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@leofcoin/standards",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Contract standards",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./exports/index.js",
|
|
9
|
+
"types": "./exports/index.d.ts"
|
|
10
|
+
},
|
|
11
|
+
"./token": {
|
|
12
|
+
"import": "./exports/token.js",
|
|
13
|
+
"types": "./exports/token.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./roles": {
|
|
16
|
+
"import": "./exports/roles.js",
|
|
17
|
+
"types": "./exports/roles.d.ts"
|
|
18
|
+
},
|
|
19
|
+
"./public-voting": {
|
|
20
|
+
"import": "./exports/public-voting.js",
|
|
21
|
+
"types": "./exports/public-voting.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./private-voting": {
|
|
24
|
+
"import": "./exports/private-voting.js",
|
|
25
|
+
"types": "./exports/private-voting.d.ts"
|
|
26
|
+
},
|
|
27
|
+
"./token-receiver": {
|
|
28
|
+
"import": "./exports/token-receiver.js",
|
|
29
|
+
"types": "./exports/token-receiver.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"./interfaces/i-public-voting": {
|
|
32
|
+
"import": "./exports/i-public-voting.js",
|
|
33
|
+
"types": "./exports/i-public-voting.d.ts"
|
|
34
|
+
},
|
|
35
|
+
"./helpers": {
|
|
36
|
+
"import": "./exports/helpers.js",
|
|
37
|
+
"types": "./exports/helpers.d.ts"
|
|
38
|
+
},
|
|
39
|
+
"./token.js": "./exports/token.js",
|
|
40
|
+
"./roles.js": "./exports/roles.js",
|
|
41
|
+
"./public-voting.js": "./exports/public-voting.js",
|
|
42
|
+
"./interfaces/i-public-voting.js": "./exports/i-public-voting.js",
|
|
43
|
+
"./private-voting.js": "./exports/private-voting.js",
|
|
44
|
+
"./helpers.js": "./exports/helpers.js"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "rollup -c",
|
|
48
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/ArteonToken/standards.git"
|
|
53
|
+
},
|
|
54
|
+
"keywords": [],
|
|
55
|
+
"author": "",
|
|
56
|
+
"license": "MIT",
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/ArteonToken/standards/issues"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://github.com/ArteonToken/standards#readme",
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@leofcoin/global-types": "^1.0.0",
|
|
63
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
64
|
+
"rollup": "^4.12.0",
|
|
65
|
+
"tslib": "^2.5.0"
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"@changesets/cli": "^2.27.1",
|
|
69
|
+
"@ethersproject/bignumber": "^5.7.0"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/rollup.config.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import typescript from '@rollup/plugin-typescript'
|
|
2
|
-
import tsConfig from './tsconfig.json' assert { type: 'json' }
|
|
3
2
|
import { execSync } from 'child_process'
|
|
4
3
|
|
|
5
4
|
// const templates = (await readdir('./src/templates')).map(path => join('./src/templates', path))
|
|
@@ -15,6 +14,7 @@ export default [
|
|
|
15
14
|
'src/token.ts',
|
|
16
15
|
'src/roles.ts',
|
|
17
16
|
'src/voting/public-voting.ts',
|
|
17
|
+
'src/voting/interfaces/i-public-voting.ts',
|
|
18
18
|
'src/voting/private-voting.ts',
|
|
19
19
|
'src/helpers.ts',
|
|
20
20
|
'src/token-receiver.ts'
|
|
@@ -23,6 +23,6 @@ export default [
|
|
|
23
23
|
dir: './exports',
|
|
24
24
|
format: 'es'
|
|
25
25
|
},
|
|
26
|
-
plugins: [typescript(
|
|
26
|
+
plugins: [typescript()]
|
|
27
27
|
}
|
|
28
28
|
]
|
package/src/token-receiver.ts
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
import { IPublicVoting } from './voting/interfaces/i-public-voting.js'
|
|
2
|
+
import PublicVoting from './voting/public-voting.js'
|
|
3
|
+
import { VotingState } from './voting/types.js'
|
|
4
|
+
|
|
5
|
+
export interface TokenReceiverState extends VotingState {
|
|
2
6
|
tokenToReceive: address
|
|
7
|
+
tokenReceiver: address
|
|
3
8
|
tokenAmountToReceive: typeof BigNumber
|
|
9
|
+
voteType: 'burn' | 'transfer'
|
|
4
10
|
}
|
|
5
|
-
export default class TokenReceiver {
|
|
11
|
+
export default class TokenReceiver extends PublicVoting implements IPublicVoting {
|
|
6
12
|
#tokenToReceive: address
|
|
7
13
|
#tokenAmountToReceive: typeof BigNumber
|
|
8
|
-
|
|
14
|
+
#tokenReceiver: address
|
|
15
|
+
#voteType: TokenReceiverState['voteType'] = 'transfer'
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
tokenToReceive: address,
|
|
19
|
+
tokenAmountToReceive: typeof BigNumber,
|
|
20
|
+
burns: boolean,
|
|
21
|
+
state?: TokenReceiverState
|
|
22
|
+
) {
|
|
23
|
+
super(state)
|
|
9
24
|
if (state) {
|
|
25
|
+
this.#tokenReceiver = state.tokenReceiver
|
|
10
26
|
this.#tokenToReceive = state.tokenToReceive
|
|
11
27
|
this.#tokenAmountToReceive = BigNumber['from'](state.tokenAmountToReceive)
|
|
28
|
+
this.#voteType = state.voteType
|
|
12
29
|
} else {
|
|
30
|
+
this.#tokenReceiver = msg.contract
|
|
13
31
|
this.#tokenToReceive = tokenToReceive
|
|
14
32
|
this.#tokenAmountToReceive = BigNumber['from'](tokenAmountToReceive)
|
|
33
|
+
if (burns) this.#voteType = 'burn'
|
|
15
34
|
}
|
|
16
35
|
}
|
|
17
36
|
|
|
@@ -23,19 +42,135 @@ export default class TokenReceiver {
|
|
|
23
42
|
return this.#tokenAmountToReceive
|
|
24
43
|
}
|
|
25
44
|
|
|
45
|
+
get tokenReceiver() {
|
|
46
|
+
return this.#tokenReceiver
|
|
47
|
+
}
|
|
48
|
+
|
|
26
49
|
get state() {
|
|
27
50
|
return {
|
|
51
|
+
...super.state,
|
|
52
|
+
tokenReceiver: this.#tokenReceiver,
|
|
28
53
|
tokenToReceive: this.#tokenToReceive,
|
|
29
|
-
tokenAmountToReceive: this.#tokenAmountToReceive
|
|
54
|
+
tokenAmountToReceive: this.#tokenAmountToReceive,
|
|
55
|
+
voteType: this.#voteType
|
|
30
56
|
}
|
|
31
57
|
}
|
|
32
58
|
|
|
59
|
+
async #canVote() {
|
|
60
|
+
const amount = (await msg.staticCall(this.#tokenToReceive, 'balanceOf', [msg.sender])) as typeof BigNumber
|
|
61
|
+
return amount.gte(this.#tokenAmountToReceive)
|
|
62
|
+
}
|
|
63
|
+
|
|
33
64
|
/**
|
|
34
65
|
* check if sender can pay
|
|
35
66
|
* @returns {boolean} promise
|
|
36
67
|
*/
|
|
37
|
-
async
|
|
38
|
-
|
|
39
|
-
|
|
68
|
+
async _canVote(): Promise<boolean> {
|
|
69
|
+
return this.#canVote()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async #beforeVote(): Promise<any> {
|
|
73
|
+
if (this.#voteType === 'burn') return msg.staticCall(this.tokenToReceive, 'burn', [this.tokenAmountToReceive])
|
|
74
|
+
return msg.staticCall(this.tokenToReceive, 'transfer', [msg.sender, this.tokenReceiver, this.tokenAmountToReceive])
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async _beforeVote(): Promise<any> {
|
|
78
|
+
await this.#beforeVote()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* check if sender can pay
|
|
83
|
+
* @returns {boolean} promise
|
|
84
|
+
*/
|
|
85
|
+
async _payTokenToReceive(): Promise<boolean> {
|
|
86
|
+
return msg.staticCall(this.#tokenToReceive, 'transfer', [
|
|
87
|
+
msg.sender,
|
|
88
|
+
this.#tokenReceiver,
|
|
89
|
+
this.#tokenAmountToReceive
|
|
90
|
+
])
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* check if sender can pay
|
|
95
|
+
* @returns {boolean} promise
|
|
96
|
+
*/
|
|
97
|
+
async _burnTokenToReceive(): Promise<boolean> {
|
|
98
|
+
return msg.staticCall(this.#tokenToReceive, 'burn', [this.#tokenAmountToReceive])
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
#changeTokenToReceive(address: address) {
|
|
102
|
+
this.#tokenToReceive = address
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
#changeTokenAmountToReceive(amount: typeof BigNumber) {
|
|
106
|
+
this.#tokenAmountToReceive = amount
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
#changeVoteType(type: TokenReceiverState['voteType']) {
|
|
110
|
+
this.#voteType = type
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#getTokensOut(amount: typeof BigNumber, receiver: address) {
|
|
114
|
+
return msg.call(this.#tokenReceiver, 'transfer', [this.#tokenReceiver, receiver, amount])
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async changeVoteType(type: TokenReceiverState['voteType']) {
|
|
118
|
+
if (!this.#canVote()) throw new Error('not a allowed')
|
|
119
|
+
if (this.#voteType === 'transfer' && (await this.#balance()).gt(0))
|
|
120
|
+
throw new Error('get tokens out first or they be lost forever')
|
|
121
|
+
else {
|
|
122
|
+
this.createVote(
|
|
123
|
+
`change the token amount to receive`,
|
|
124
|
+
`set tokenAmountToReceive`,
|
|
125
|
+
new Date().getTime() + this.votingDuration,
|
|
126
|
+
'#changeVoteType',
|
|
127
|
+
[type]
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getTokensOut(amount: typeof BigNumber, receiver: address) {
|
|
133
|
+
if (!this.#canVote()) throw new Error('not a allowed')
|
|
134
|
+
else {
|
|
135
|
+
this.createVote(
|
|
136
|
+
`withdraw all tokens`,
|
|
137
|
+
`withdraw all tokens to ${receiver}`,
|
|
138
|
+
new Date().getTime() + this.votingDuration,
|
|
139
|
+
'#getTokensOut',
|
|
140
|
+
[amount, receiver]
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
changeTokenAmountToReceive() {
|
|
146
|
+
if (!this.#canVote()) throw new Error('not a allowed')
|
|
147
|
+
else {
|
|
148
|
+
this.createVote(
|
|
149
|
+
`change the token amount to receive`,
|
|
150
|
+
`set tokenAmountToReceive`,
|
|
151
|
+
new Date().getTime() + this.votingDuration,
|
|
152
|
+
'#changeTokenAmountToReceive',
|
|
153
|
+
[]
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
#balance(): Promise<typeof BigNumber> {
|
|
159
|
+
return msg.staticCall(this.#tokenToReceive, 'balanceOf', [this.#tokenReceiver])
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async changeTokenToReceive() {
|
|
163
|
+
if (!this.#canVote()) throw new Error('not a allowed')
|
|
164
|
+
if (!(await this.#balance()).eq(0) && this.#voteType === 'transfer')
|
|
165
|
+
throw new Error('get tokens out first or they be lost forever')
|
|
166
|
+
else {
|
|
167
|
+
this.createVote(
|
|
168
|
+
`change the token to receive`,
|
|
169
|
+
`set tokenToReceive to a new address`,
|
|
170
|
+
new Date().getTime() + this.votingDuration,
|
|
171
|
+
'#changeTokenToReceive',
|
|
172
|
+
[]
|
|
173
|
+
)
|
|
174
|
+
}
|
|
40
175
|
}
|
|
41
176
|
}
|
package/src/token.ts
CHANGED
|
@@ -90,6 +90,10 @@ export default class Token extends Roles {
|
|
|
90
90
|
return { ...this.#balances }
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
get approvals() {
|
|
94
|
+
return this.#approvals
|
|
95
|
+
}
|
|
96
|
+
|
|
93
97
|
get decimals() {
|
|
94
98
|
return this.#decimals
|
|
95
99
|
}
|
|
@@ -132,6 +136,10 @@ export default class Token extends Roles {
|
|
|
132
136
|
this.#updateHolders(address, previousBalance)
|
|
133
137
|
}
|
|
134
138
|
|
|
139
|
+
balance() {
|
|
140
|
+
return this.#balances[msg.sender]
|
|
141
|
+
}
|
|
142
|
+
|
|
135
143
|
balanceOf(address: address): BigNumberish {
|
|
136
144
|
return this.#balances[address]
|
|
137
145
|
}
|
|
@@ -1,25 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type Vote = {
|
|
4
|
-
title: string
|
|
5
|
-
method: string
|
|
6
|
-
args: any[]
|
|
7
|
-
description: string
|
|
8
|
-
endTime: EpochTimeStamp
|
|
9
|
-
results?: { [address: address]: VoteResult }
|
|
10
|
-
finished?: boolean
|
|
11
|
-
enoughVotes?: boolean
|
|
12
|
-
}
|
|
1
|
+
import { VoteResult, VoteView, VotingState } from './types.js'
|
|
13
2
|
|
|
14
|
-
export
|
|
15
|
-
voters
|
|
16
|
-
votes: {
|
|
17
|
-
[id: string]: Vote
|
|
18
|
-
}
|
|
19
|
-
votingDisabled: boolean
|
|
20
|
-
}
|
|
21
|
-
export interface VoteView extends Vote {
|
|
22
|
-
id: string
|
|
3
|
+
export interface PrivateVotingState extends VotingState {
|
|
4
|
+
voters
|
|
23
5
|
}
|
|
24
6
|
|
|
25
7
|
export default class PrivateVoting {
|
|
@@ -1,38 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import PrivateVoting from './private-voting.js'
|
|
3
|
-
|
|
4
|
-
export type VoteResult = 0 | 0.5 | 1
|
|
5
|
-
|
|
6
|
-
export type PublicVote = {
|
|
7
|
-
title: string
|
|
8
|
-
method: string
|
|
9
|
-
args: any[]
|
|
10
|
-
description: string
|
|
11
|
-
endTime: EpochTimeStamp
|
|
12
|
-
results?: { [address: address]: VoteResult }
|
|
13
|
-
finished?: boolean
|
|
14
|
-
enoughVotes?: boolean
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface PublicVotingState extends TokenReceiverState {
|
|
18
|
-
votes: {
|
|
19
|
-
[id: string]: PublicVote
|
|
20
|
-
}
|
|
21
|
-
votingDisabled: boolean
|
|
22
|
-
}
|
|
23
|
-
export interface VoteView extends PublicVote {
|
|
24
|
-
id: string
|
|
25
|
-
}
|
|
1
|
+
import { VotingState, VoteResult } from './types.js'
|
|
26
2
|
|
|
27
3
|
/**
|
|
28
4
|
* allows everybody that has a balance greater or equeal then/to tokenAmountToReceive to vote
|
|
29
5
|
*/
|
|
30
|
-
export default class PublicVoting
|
|
31
|
-
#votes:
|
|
6
|
+
export default class PublicVoting {
|
|
7
|
+
#votes: VotingState['votes']
|
|
32
8
|
#votingDisabled: boolean
|
|
9
|
+
#votingDuration: number = 172800000
|
|
33
10
|
|
|
34
|
-
constructor(
|
|
35
|
-
super(tokenToReceive, tokenAmountToReceive, state)
|
|
11
|
+
constructor(state: VotingState) {
|
|
36
12
|
if (state) {
|
|
37
13
|
this.#votes = state.votes
|
|
38
14
|
this.#votingDisabled = state.votingDisabled
|
|
@@ -43,6 +19,10 @@ export default class PublicVoting extends TokenReceiver {
|
|
|
43
19
|
return { ...this.#votes }
|
|
44
20
|
}
|
|
45
21
|
|
|
22
|
+
get votingDuration() {
|
|
23
|
+
return this.#votingDuration
|
|
24
|
+
}
|
|
25
|
+
|
|
46
26
|
get votingDisabled() {
|
|
47
27
|
return this.#votingDisabled
|
|
48
28
|
}
|
|
@@ -50,11 +30,11 @@ export default class PublicVoting extends TokenReceiver {
|
|
|
50
30
|
/**
|
|
51
31
|
*
|
|
52
32
|
*/
|
|
53
|
-
get state()
|
|
54
|
-
return {
|
|
33
|
+
get state() {
|
|
34
|
+
return { votes: this.#votes, votingDisabled: this.#votingDisabled, votingDuration: this.#votingDuration }
|
|
55
35
|
}
|
|
56
36
|
|
|
57
|
-
get inProgress()
|
|
37
|
+
get inProgress() {
|
|
58
38
|
return Object.entries(this.#votes)
|
|
59
39
|
.filter(([id, vote]) => !vote.finished)
|
|
60
40
|
.map(([id, vote]) => {
|
|
@@ -70,7 +50,7 @@ export default class PublicVoting extends TokenReceiver {
|
|
|
70
50
|
*/
|
|
71
51
|
|
|
72
52
|
createVote(title: string, description: string, endTime: EpochTimeStamp, method: string, args: any[] = []) {
|
|
73
|
-
if (!this
|
|
53
|
+
if (!this.#canVote()) throw new Error(`Not allowed to create a vote`)
|
|
74
54
|
const id = crypto.randomUUID()
|
|
75
55
|
this.#votes[id] = {
|
|
76
56
|
title,
|
|
@@ -81,8 +61,14 @@ export default class PublicVoting extends TokenReceiver {
|
|
|
81
61
|
}
|
|
82
62
|
}
|
|
83
63
|
|
|
84
|
-
canVote(
|
|
85
|
-
|
|
64
|
+
#canVote() {
|
|
65
|
+
// @ts-expect-error
|
|
66
|
+
return this._canVote?.()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#beforeVote() {
|
|
70
|
+
// @ts-expect-error
|
|
71
|
+
return this._beforeVote?.()
|
|
86
72
|
}
|
|
87
73
|
|
|
88
74
|
#endVoting(voteId) {
|
|
@@ -100,8 +86,8 @@ export default class PublicVoting extends TokenReceiver {
|
|
|
100
86
|
const ended = new Date().getTime() > this.#votes[voteId].endTime
|
|
101
87
|
if (ended && !this.#votes[voteId].finished) this.#endVoting(voteId)
|
|
102
88
|
if (ended) throw new Error('voting already ended')
|
|
103
|
-
if (!this
|
|
104
|
-
await
|
|
89
|
+
if (!this.#canVote()) throw new Error(`Not allowed to vote`)
|
|
90
|
+
await this.#beforeVote()
|
|
105
91
|
this.#votes[voteId][msg.sender] = vote
|
|
106
92
|
}
|
|
107
93
|
|
|
@@ -110,19 +96,19 @@ export default class PublicVoting extends TokenReceiver {
|
|
|
110
96
|
}
|
|
111
97
|
|
|
112
98
|
disableVoting() {
|
|
113
|
-
if (!this
|
|
99
|
+
if (!this.#canVote()) throw new Error('not a allowed')
|
|
114
100
|
else {
|
|
115
101
|
this.createVote(
|
|
116
102
|
`disable voting`,
|
|
117
103
|
`Warning this disables all voting features forever`,
|
|
118
|
-
new Date().getTime() +
|
|
104
|
+
new Date().getTime() + this.#votingDuration,
|
|
119
105
|
'#disableVoting',
|
|
120
106
|
[]
|
|
121
107
|
)
|
|
122
108
|
}
|
|
123
109
|
}
|
|
124
110
|
|
|
125
|
-
|
|
111
|
+
_sync() {
|
|
126
112
|
for (const vote of this.inProgress) {
|
|
127
113
|
if (vote.endTime < new Date().getTime()) this.#endVoting(vote.id)
|
|
128
114
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type VoteResult = 0 | 0.5 | 1
|
|
2
|
+
|
|
3
|
+
export type Vote = {
|
|
4
|
+
title: string
|
|
5
|
+
method: string
|
|
6
|
+
args: any[]
|
|
7
|
+
description: string
|
|
8
|
+
endTime: EpochTimeStamp
|
|
9
|
+
results?: { [address: string]: VoteResult }
|
|
10
|
+
finished?: boolean
|
|
11
|
+
enoughVotes?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface VotingState {
|
|
15
|
+
votes: {
|
|
16
|
+
[id: string]: Vote
|
|
17
|
+
}
|
|
18
|
+
votingDisabled: boolean
|
|
19
|
+
votingDuration: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface VoteView extends Vote {
|
|
23
|
+
id: string
|
|
24
|
+
}
|