@openzeppelin/wizard 0.4.1 → 0.4.3
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/dist/contract.d.ts +2 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +8 -0
- package/dist/contract.js.map +1 -1
- package/dist/environments/hardhat/package-lock.json +2999 -5190
- package/dist/environments/hardhat/package.json +1 -1
- package/dist/environments/hardhat/upgradeable/package-lock.json +1875 -3396
- package/dist/environments/hardhat/upgradeable/package.json +2 -2
- package/dist/erc20.d.ts +6 -1
- package/dist/erc20.d.ts.map +1 -1
- package/dist/erc20.js +5 -2
- package/dist/erc20.js.map +1 -1
- package/dist/erc721.d.ts +6 -1
- package/dist/erc721.d.ts.map +1 -1
- package/dist/erc721.js +6 -3
- package/dist/erc721.js.map +1 -1
- package/dist/generate/erc20.d.ts.map +1 -1
- package/dist/generate/erc20.js +2 -1
- package/dist/generate/erc20.js.map +1 -1
- package/dist/generate/erc721.d.ts.map +1 -1
- package/dist/generate/erc721.js +2 -1
- package/dist/generate/erc721.js.map +1 -1
- package/dist/generate/governor.d.ts.map +1 -1
- package/dist/generate/governor.js +2 -0
- package/dist/generate/governor.js.map +1 -1
- package/dist/generate/sources.d.ts +5 -4
- package/dist/generate/sources.d.ts.map +1 -1
- package/dist/generate/sources.js +27 -17
- package/dist/generate/sources.js.map +1 -1
- package/dist/governor.d.ts +2 -0
- package/dist/governor.d.ts.map +1 -1
- package/dist/governor.js +41 -8
- package/dist/governor.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +6 -4
- package/dist/print.js.map +1 -1
- package/dist/set-clock-mode.d.ts +6 -0
- package/dist/set-clock-mode.d.ts.map +1 -0
- package/dist/set-clock-mode.js +31 -0
- package/dist/set-clock-mode.js.map +1 -0
- package/dist/test.js +23 -5
- package/dist/test.js.map +1 -1
- package/dist/utils/duration.d.ts +1 -0
- package/dist/utils/duration.d.ts.map +1 -1
- package/dist/utils/duration.js +15 -1
- package/dist/utils/duration.js.map +1 -1
- package/dist/utils/version.d.ts +5 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +8 -0
- package/dist/utils/version.js.map +1 -0
- package/dist/zip-foundry.d.ts.map +1 -1
- package/dist/zip-foundry.js +141 -32
- package/dist/zip-foundry.js.map +1 -1
- package/package.json +5 -3
- package/src/contract.ts +10 -0
- package/src/environments/hardhat/package-lock.json +2999 -5190
- package/src/environments/hardhat/package.json +1 -1
- package/src/environments/hardhat/upgradeable/package-lock.json +1875 -3396
- package/src/environments/hardhat/upgradeable/package.json +2 -2
- package/src/erc20.ts +11 -3
- package/src/erc721.ts +12 -4
- package/src/generate/erc20.ts +2 -1
- package/src/generate/erc721.ts +2 -1
- package/src/generate/governor.ts +2 -0
- package/src/generate/sources.ts +30 -18
- package/src/governor.ts +40 -10
- package/src/index.ts +3 -1
- package/src/print.ts +6 -2
- package/src/set-clock-mode.ts +33 -0
- package/src/test.ts +34 -6
- package/src/utils/duration.ts +18 -0
- package/src/utils/version.ts +4 -0
- package/src/zip-foundry.ts +141 -34
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@openzeppelin/contracts": "^5.0.0",
|
|
13
13
|
"@openzeppelin/contracts-upgradeable": "^5.0.0",
|
|
14
|
-
"@openzeppelin/hardhat-upgrades": "^
|
|
15
|
-
"@nomicfoundation/hardhat-toolbox": "^
|
|
14
|
+
"@openzeppelin/hardhat-upgrades": "^3.0.0",
|
|
15
|
+
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
|
|
16
16
|
"hardhat": "^2.16.1"
|
|
17
17
|
}
|
|
18
18
|
}
|
package/src/erc20.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from '.
|
|
|
6
6
|
import { setUpgradeable } from './set-upgradeable';
|
|
7
7
|
import { setInfo } from './set-info';
|
|
8
8
|
import { printContract } from './print';
|
|
9
|
+
import { ClockMode, clockModeDefault, setClockMode } from './set-clock-mode';
|
|
9
10
|
|
|
10
11
|
export interface ERC20Options extends CommonOptions {
|
|
11
12
|
name: string;
|
|
@@ -15,7 +16,11 @@ export interface ERC20Options extends CommonOptions {
|
|
|
15
16
|
premint?: string;
|
|
16
17
|
mintable?: boolean;
|
|
17
18
|
permit?: boolean;
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Whether to keep track of historical balances for voting in on-chain governance, and optionally specify the clock mode.
|
|
21
|
+
* Setting `true` is equivalent to 'blocknumber'. Setting a clock mode implies voting is enabled.
|
|
22
|
+
*/
|
|
23
|
+
votes?: boolean | ClockMode;
|
|
19
24
|
flashmint?: boolean;
|
|
20
25
|
}
|
|
21
26
|
|
|
@@ -87,7 +92,8 @@ export function buildERC20(opts: ERC20Options): Contract {
|
|
|
87
92
|
}
|
|
88
93
|
|
|
89
94
|
if (allOpts.votes) {
|
|
90
|
-
|
|
95
|
+
const clockMode = allOpts.votes === true ? clockModeDefault : allOpts.votes;
|
|
96
|
+
addVotes(c, clockMode);
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
if (allOpts.flashmint) {
|
|
@@ -166,7 +172,7 @@ function addPermit(c: ContractBuilder, name: string) {
|
|
|
166
172
|
|
|
167
173
|
}
|
|
168
174
|
|
|
169
|
-
function addVotes(c: ContractBuilder) {
|
|
175
|
+
function addVotes(c: ContractBuilder, clockMode: ClockMode) {
|
|
170
176
|
if (!c.parents.some(p => p.contract.name === 'ERC20Permit')) {
|
|
171
177
|
throw new Error('Missing ERC20Permit requirement for ERC20Votes');
|
|
172
178
|
}
|
|
@@ -180,6 +186,8 @@ function addVotes(c: ContractBuilder) {
|
|
|
180
186
|
c.addOverride({
|
|
181
187
|
name: 'Nonces',
|
|
182
188
|
}, functions.nonces);
|
|
189
|
+
|
|
190
|
+
setClockMode(c, ERC20Votes, clockMode);
|
|
183
191
|
}
|
|
184
192
|
|
|
185
193
|
function addFlashMint(c: ContractBuilder) {
|
package/src/erc721.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from '.
|
|
|
7
7
|
import { setUpgradeable } from './set-upgradeable';
|
|
8
8
|
import { setInfo } from './set-info';
|
|
9
9
|
import { printContract } from './print';
|
|
10
|
+
import { ClockMode, clockModeDefault, setClockMode } from './set-clock-mode';
|
|
10
11
|
|
|
11
12
|
export interface ERC721Options extends CommonOptions {
|
|
12
13
|
name: string;
|
|
@@ -18,7 +19,11 @@ export interface ERC721Options extends CommonOptions {
|
|
|
18
19
|
pausable?: boolean;
|
|
19
20
|
mintable?: boolean;
|
|
20
21
|
incremental?: boolean;
|
|
21
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Whether to keep track of individual units for voting in on-chain governance, and optionally specify the clock mode.
|
|
24
|
+
* Setting `true` is equivalent to 'blocknumber'. Setting a clock mode implies voting is enabled.
|
|
25
|
+
*/
|
|
26
|
+
votes?: boolean | ClockMode;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
export const defaults: Required<ERC721Options> = {
|
|
@@ -34,7 +39,7 @@ export const defaults: Required<ERC721Options> = {
|
|
|
34
39
|
votes: false,
|
|
35
40
|
access: commonDefaults.access,
|
|
36
41
|
upgradeable: commonDefaults.upgradeable,
|
|
37
|
-
info: commonDefaults.info
|
|
42
|
+
info: commonDefaults.info,
|
|
38
43
|
} as const;
|
|
39
44
|
|
|
40
45
|
function withDefaults(opts: ERC721Options): Required<ERC721Options> {
|
|
@@ -94,7 +99,8 @@ export function buildERC721(opts: ERC721Options): Contract {
|
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
if (allOpts.votes) {
|
|
97
|
-
|
|
102
|
+
const clockMode = allOpts.votes === true ? clockModeDefault : allOpts.votes;
|
|
103
|
+
addVotes(c, allOpts.name, clockMode);
|
|
98
104
|
}
|
|
99
105
|
|
|
100
106
|
setAccessControl(c, access);
|
|
@@ -181,7 +187,7 @@ function addMintable(c: ContractBuilder, access: Access, incremental = false, ur
|
|
|
181
187
|
}
|
|
182
188
|
}
|
|
183
189
|
|
|
184
|
-
function addVotes(c: ContractBuilder, name: string) {
|
|
190
|
+
function addVotes(c: ContractBuilder, name: string, clockMode: ClockMode) {
|
|
185
191
|
const EIP712 = {
|
|
186
192
|
name: 'EIP712',
|
|
187
193
|
path: '@openzeppelin/contracts/utils/cryptography/EIP712.sol',
|
|
@@ -196,6 +202,8 @@ function addVotes(c: ContractBuilder, name: string) {
|
|
|
196
202
|
|
|
197
203
|
c.addOverride(ERC721Votes, functions._update);
|
|
198
204
|
c.addOverride(ERC721Votes, functions._increaseBalance);
|
|
205
|
+
|
|
206
|
+
setClockMode(c, ERC721Votes, clockMode);
|
|
199
207
|
}
|
|
200
208
|
|
|
201
209
|
const functions = defineFunctions({
|
package/src/generate/erc20.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ERC20Options } from '../erc20';
|
|
2
2
|
import { accessOptions } from '../set-access-control';
|
|
3
|
+
import { clockModeOptions } from '../set-clock-mode';
|
|
3
4
|
import { infoOptions } from '../set-info';
|
|
4
5
|
import { upgradeableOptions } from '../set-upgradeable';
|
|
5
6
|
import { generateAlternatives } from './alternatives';
|
|
@@ -13,7 +14,7 @@ const blueprint = {
|
|
|
13
14
|
pausable: booleans,
|
|
14
15
|
mintable: booleans,
|
|
15
16
|
permit: booleans,
|
|
16
|
-
votes: booleans,
|
|
17
|
+
votes: [ ...booleans, ...clockModeOptions ] as const,
|
|
17
18
|
flashmint: booleans,
|
|
18
19
|
premint: ['1'],
|
|
19
20
|
access: accessOptions,
|
package/src/generate/erc721.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ERC721Options } from '../erc721';
|
|
2
2
|
import { accessOptions } from '../set-access-control';
|
|
3
|
+
import { clockModeOptions } from '../set-clock-mode';
|
|
3
4
|
import { infoOptions } from '../set-info';
|
|
4
5
|
import { upgradeableOptions } from '../set-upgradeable';
|
|
5
6
|
import { generateAlternatives } from './alternatives';
|
|
@@ -19,7 +20,7 @@ const blueprint = {
|
|
|
19
20
|
access: accessOptions,
|
|
20
21
|
upgradeable: upgradeableOptions,
|
|
21
22
|
info: infoOptions,
|
|
22
|
-
votes: booleans,
|
|
23
|
+
votes: [ ...booleans, ...clockModeOptions ] as const,
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
export function* generateERC721Options(): Generator<Required<ERC721Options>> {
|
package/src/generate/governor.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defaults, GovernorOptions, timelockOptions, votesOptions } from '../governor';
|
|
2
2
|
import { accessOptions } from '../set-access-control';
|
|
3
|
+
import { clockModeOptions } from '../set-clock-mode';
|
|
3
4
|
import { infoOptions } from '../set-info';
|
|
4
5
|
import { upgradeableOptions } from '../set-upgradeable';
|
|
5
6
|
import { generateAlternatives } from './alternatives';
|
|
@@ -17,6 +18,7 @@ const blueprint = {
|
|
|
17
18
|
quorumPercent: [4],
|
|
18
19
|
quorumAbsolute: ['1000'],
|
|
19
20
|
votes: votesOptions,
|
|
21
|
+
clockMode: clockModeOptions,
|
|
20
22
|
timelock: timelockOptions,
|
|
21
23
|
storage: booleans,
|
|
22
24
|
settings: booleans,
|
package/src/generate/sources.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { generateERC721Options } from './erc721';
|
|
|
7
7
|
import { generateERC1155Options } from './erc1155';
|
|
8
8
|
import { generateGovernorOptions } from './governor';
|
|
9
9
|
import { generateCustomOptions } from './custom';
|
|
10
|
-
import { buildGeneric, GenericOptions } from '../build-generic';
|
|
10
|
+
import { buildGeneric, GenericOptions, KindedOptions } from '../build-generic';
|
|
11
11
|
import { printContract } from '../print';
|
|
12
12
|
import { OptionsError } from '../error';
|
|
13
13
|
import { findCover } from '../utils/find-cover';
|
|
@@ -15,25 +15,37 @@ import type { Contract } from '../contract';
|
|
|
15
15
|
|
|
16
16
|
type Subset = 'all' | 'minimal-cover';
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
type Kind = keyof KindedOptions;
|
|
19
|
+
|
|
20
|
+
export function* generateOptions(kind?: Kind): Generator<GenericOptions> {
|
|
21
|
+
if (!kind || kind === 'ERC20') {
|
|
22
|
+
for (const kindOpts of generateERC20Options()) {
|
|
23
|
+
yield { kind: 'ERC20', ...kindOpts };
|
|
24
|
+
}
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
if (!kind || kind === 'ERC721') {
|
|
28
|
+
for (const kindOpts of generateERC721Options()) {
|
|
29
|
+
yield { kind: 'ERC721', ...kindOpts };
|
|
30
|
+
}
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
if (!kind || kind === 'ERC1155') {
|
|
34
|
+
for (const kindOpts of generateERC1155Options()) {
|
|
35
|
+
yield { kind: 'ERC1155', ...kindOpts };
|
|
36
|
+
}
|
|
29
37
|
}
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
if (!kind || kind === 'Governor') {
|
|
40
|
+
for (const kindOpts of generateGovernorOptions()) {
|
|
41
|
+
yield { kind: 'Governor', ...kindOpts };
|
|
42
|
+
}
|
|
33
43
|
}
|
|
34
44
|
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
if (!kind || kind === 'Custom') {
|
|
46
|
+
for (const kindOpts of generateCustomOptions()) {
|
|
47
|
+
yield { kind: 'Custom', ...kindOpts };
|
|
48
|
+
}
|
|
37
49
|
}
|
|
38
50
|
}
|
|
39
51
|
|
|
@@ -47,10 +59,10 @@ interface GeneratedSource extends GeneratedContract {
|
|
|
47
59
|
source: string;
|
|
48
60
|
}
|
|
49
61
|
|
|
50
|
-
function generateContractSubset(subset: Subset): GeneratedContract[] {
|
|
62
|
+
function generateContractSubset(subset: Subset, kind?: Kind): GeneratedContract[] {
|
|
51
63
|
const contracts = [];
|
|
52
64
|
|
|
53
|
-
for (const options of generateOptions()) {
|
|
65
|
+
for (const options of generateOptions(kind)) {
|
|
54
66
|
const id = crypto
|
|
55
67
|
.createHash('sha1')
|
|
56
68
|
.update(JSON.stringify(options))
|
|
@@ -80,17 +92,17 @@ function generateContractSubset(subset: Subset): GeneratedContract[] {
|
|
|
80
92
|
}
|
|
81
93
|
}
|
|
82
94
|
|
|
83
|
-
export function* generateSources(subset: Subset): Generator<GeneratedSource> {
|
|
84
|
-
for (const c of generateContractSubset(subset)) {
|
|
95
|
+
export function* generateSources(subset: Subset, kind?: Kind): Generator<GeneratedSource> {
|
|
96
|
+
for (const c of generateContractSubset(subset, kind)) {
|
|
85
97
|
const source = printContract(c.contract);
|
|
86
98
|
yield { ...c, source };
|
|
87
99
|
}
|
|
88
100
|
}
|
|
89
101
|
|
|
90
|
-
export async function writeGeneratedSources(dir: string, subset: Subset): Promise<void> {
|
|
102
|
+
export async function writeGeneratedSources(dir: string, subset: Subset, kind?: Kind): Promise<void> {
|
|
91
103
|
await fs.mkdir(dir, { recursive: true });
|
|
92
104
|
|
|
93
|
-
for (const { id, source } of generateSources(subset)) {
|
|
105
|
+
for (const { id, source } of generateSources(subset, kind)) {
|
|
94
106
|
await fs.writeFile(path.format({ dir, name: id, ext: '.sol' }), source);
|
|
95
107
|
}
|
|
96
108
|
}
|
package/src/governor.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { supportsInterface } from "./common-functions";
|
|
2
2
|
import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from "./common-options";
|
|
3
|
-
import { ContractBuilder, Contract } from "./contract";
|
|
3
|
+
import { ContractBuilder, Contract, Value } from "./contract";
|
|
4
4
|
import { OptionsError } from "./error";
|
|
5
5
|
import { setAccessControl } from "./set-access-control";
|
|
6
6
|
import { printContract } from "./print";
|
|
7
7
|
import { setInfo } from "./set-info";
|
|
8
8
|
import { setUpgradeable } from "./set-upgradeable";
|
|
9
9
|
import { defineFunctions } from './utils/define-functions';
|
|
10
|
-
import { durationToBlocks } from "./utils/duration";
|
|
10
|
+
import { durationToBlocks, durationToTimestamp } from "./utils/duration";
|
|
11
|
+
import { clockModeDefault, type ClockMode } from "./set-clock-mode";
|
|
11
12
|
|
|
12
13
|
export const defaults: Required<GovernorOptions> = {
|
|
13
14
|
name: 'MyGovernor',
|
|
@@ -15,6 +16,7 @@ export const defaults: Required<GovernorOptions> = {
|
|
|
15
16
|
period: '1 week',
|
|
16
17
|
|
|
17
18
|
votes: 'erc20votes',
|
|
19
|
+
clockMode: clockModeDefault,
|
|
18
20
|
timelock: 'openzeppelin',
|
|
19
21
|
blockTime: 12,
|
|
20
22
|
decimals: 18,
|
|
@@ -51,6 +53,7 @@ export interface GovernorOptions extends CommonOptions {
|
|
|
51
53
|
quorumPercent?: number;
|
|
52
54
|
quorumAbsolute?: string;
|
|
53
55
|
votes?: VotesOptions;
|
|
56
|
+
clockMode?: ClockMode;
|
|
54
57
|
timelock?: TimelockOptions;
|
|
55
58
|
storage?: boolean;
|
|
56
59
|
settings?: boolean;
|
|
@@ -73,6 +76,7 @@ function withDefaults(opts: GovernorOptions): Required<GovernorOptions> {
|
|
|
73
76
|
storage: opts.storage ?? defaults.storage,
|
|
74
77
|
quorumMode: opts.quorumMode ?? defaults.quorumMode,
|
|
75
78
|
votes: opts.votes ?? defaults.votes,
|
|
79
|
+
clockMode: opts.clockMode ?? defaults.clockMode,
|
|
76
80
|
timelock: opts.timelock ?? defaults.timelock
|
|
77
81
|
};
|
|
78
82
|
}
|
|
@@ -129,8 +133,8 @@ function addSettings(c: ContractBuilder, allOpts: Required<GovernorOptions>) {
|
|
|
129
133
|
c.addParent(
|
|
130
134
|
GovernorSettings,
|
|
131
135
|
[
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
getVotingDelay(allOpts),
|
|
137
|
+
getVotingPeriod(allOpts),
|
|
134
138
|
{ lit: getProposalThreshold(allOpts) },
|
|
135
139
|
],
|
|
136
140
|
);
|
|
@@ -143,9 +147,18 @@ function addSettings(c: ContractBuilder, allOpts: Required<GovernorOptions>) {
|
|
|
143
147
|
}
|
|
144
148
|
}
|
|
145
149
|
|
|
146
|
-
function getVotingDelay(opts: Required<GovernorOptions>): number {
|
|
150
|
+
function getVotingDelay(opts: Required<GovernorOptions>): { lit: string } | { note: string, value: number } {
|
|
147
151
|
try {
|
|
148
|
-
|
|
152
|
+
if (opts.clockMode === 'timestamp') {
|
|
153
|
+
return {
|
|
154
|
+
lit: durationToTimestamp(opts.delay),
|
|
155
|
+
};
|
|
156
|
+
} else {
|
|
157
|
+
return {
|
|
158
|
+
value: durationToBlocks(opts.delay, opts.blockTime),
|
|
159
|
+
note: opts.delay
|
|
160
|
+
};
|
|
161
|
+
}
|
|
149
162
|
} catch (e) {
|
|
150
163
|
if (e instanceof Error) {
|
|
151
164
|
throw new OptionsError({
|
|
@@ -157,9 +170,18 @@ function getVotingDelay(opts: Required<GovernorOptions>): number {
|
|
|
157
170
|
}
|
|
158
171
|
}
|
|
159
172
|
|
|
160
|
-
function getVotingPeriod(opts: Required<GovernorOptions>): number {
|
|
173
|
+
function getVotingPeriod(opts: Required<GovernorOptions>): { lit: string } | { note: string, value: number } {
|
|
161
174
|
try {
|
|
162
|
-
|
|
175
|
+
if (opts.clockMode === 'timestamp') {
|
|
176
|
+
return {
|
|
177
|
+
lit: durationToTimestamp(opts.period),
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
return {
|
|
181
|
+
value: durationToBlocks(opts.period, opts.blockTime),
|
|
182
|
+
note: opts.period
|
|
183
|
+
};
|
|
184
|
+
}
|
|
163
185
|
} catch (e) {
|
|
164
186
|
if (e instanceof Error) {
|
|
165
187
|
throw new OptionsError({
|
|
@@ -195,10 +217,18 @@ function getProposalThreshold({ proposalThreshold, decimals, votes }: Required<G
|
|
|
195
217
|
|
|
196
218
|
function setVotingParameters(c: ContractBuilder, opts: Required<GovernorOptions>) {
|
|
197
219
|
const delayBlocks = getVotingDelay(opts);
|
|
198
|
-
|
|
220
|
+
if ('lit' in delayBlocks) {
|
|
221
|
+
c.setFunctionBody([`return ${delayBlocks.lit};`], functions.votingDelay);
|
|
222
|
+
} else {
|
|
223
|
+
c.setFunctionBody([`return ${delayBlocks.value}; // ${delayBlocks.note}`], functions.votingDelay);
|
|
224
|
+
}
|
|
199
225
|
|
|
200
226
|
const periodBlocks = getVotingPeriod(opts);
|
|
201
|
-
|
|
227
|
+
if ('lit' in periodBlocks) {
|
|
228
|
+
c.setFunctionBody([`return ${periodBlocks.lit};`], functions.votingPeriod);
|
|
229
|
+
} else {
|
|
230
|
+
c.setFunctionBody([`return ${periodBlocks.value}; // ${periodBlocks.note}`], functions.votingPeriod);
|
|
231
|
+
}
|
|
202
232
|
}
|
|
203
233
|
|
|
204
234
|
function setProposalThreshold(c: ContractBuilder, opts: Required<GovernorOptions>) {
|
package/src/index.ts
CHANGED
|
@@ -19,4 +19,6 @@ export { OptionsError } from './error';
|
|
|
19
19
|
export type { Kind } from './kind';
|
|
20
20
|
export { sanitizeKind } from './kind';
|
|
21
21
|
|
|
22
|
-
export { erc20, erc721, erc1155, governor, custom } from './api';
|
|
22
|
+
export { erc20, erc721, erc1155, governor, custom } from './api';
|
|
23
|
+
|
|
24
|
+
export { compatibleContractsSemver } from './utils/version';
|
package/src/print.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { formatLines, spaceBetween, Lines } from './utils/format-lines';
|
|
|
7
7
|
import { mapValues } from './utils/map-values';
|
|
8
8
|
import SOLIDITY_VERSION from './solidity-version.json';
|
|
9
9
|
import { inferTranspiled } from './infer-transpiled';
|
|
10
|
+
import { compatibleContractsSemver } from './utils/version';
|
|
10
11
|
|
|
11
12
|
export function printContract(contract: Contract, opts?: Options): string {
|
|
12
13
|
const helpers = withHelpers(contract, opts);
|
|
@@ -22,6 +23,7 @@ export function printContract(contract: Contract, opts?: Options): string {
|
|
|
22
23
|
...spaceBetween(
|
|
23
24
|
[
|
|
24
25
|
`// SPDX-License-Identifier: ${contract.license}`,
|
|
26
|
+
`// Compatible with OpenZeppelin Contracts ${compatibleContractsSemver}`,
|
|
25
27
|
`pragma solidity ^${SOLIDITY_VERSION};`,
|
|
26
28
|
],
|
|
27
29
|
|
|
@@ -71,6 +73,7 @@ function printConstructor(contract: Contract, helpers: Helpers): Lines[] {
|
|
|
71
73
|
: contract.constructorCode;
|
|
72
74
|
const head = helpers.upgradeable ? 'function initialize' : 'constructor';
|
|
73
75
|
const constructor = printFunction2(
|
|
76
|
+
[],
|
|
74
77
|
head,
|
|
75
78
|
args,
|
|
76
79
|
modifiers,
|
|
@@ -191,6 +194,7 @@ function printFunction(fn: ContractFunction, helpers: Helpers): Lines[] {
|
|
|
191
194
|
|
|
192
195
|
if (modifiers.length + fn.code.length > 1) {
|
|
193
196
|
return printFunction2(
|
|
197
|
+
fn.comments,
|
|
194
198
|
'function ' + fn.name,
|
|
195
199
|
fn.args.map(a => printArgument(a, helpers)),
|
|
196
200
|
modifiers,
|
|
@@ -203,8 +207,8 @@ function printFunction(fn: ContractFunction, helpers: Helpers): Lines[] {
|
|
|
203
207
|
|
|
204
208
|
// generic for functions and constructors
|
|
205
209
|
// kindedName = 'function foo' or 'constructor'
|
|
206
|
-
function printFunction2(kindedName: string, args: string[], modifiers: string[], code: Lines[]): Lines[] {
|
|
207
|
-
const fn = [];
|
|
210
|
+
function printFunction2(comments: string[], kindedName: string, args: string[], modifiers: string[], code: Lines[]): Lines[] {
|
|
211
|
+
const fn: Lines[] = [ ...comments ];
|
|
208
212
|
|
|
209
213
|
const headingLength = [kindedName, ...args, ...modifiers]
|
|
210
214
|
.map(s => s.length)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ContractBuilder, ReferencedContract } from "./contract";
|
|
2
|
+
import { defineFunctions } from "./utils/define-functions";
|
|
3
|
+
|
|
4
|
+
export const clockModeOptions = ['blocknumber', 'timestamp'] as const;
|
|
5
|
+
export const clockModeDefault = 'blocknumber' as const;
|
|
6
|
+
export type ClockMode = typeof clockModeOptions[number];
|
|
7
|
+
|
|
8
|
+
const functions = defineFunctions({
|
|
9
|
+
clock: {
|
|
10
|
+
kind: 'public' as const,
|
|
11
|
+
args: [],
|
|
12
|
+
returns: ['uint48'],
|
|
13
|
+
mutability: 'view' as const,
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
CLOCK_MODE: {
|
|
17
|
+
kind: 'public' as const,
|
|
18
|
+
args: [],
|
|
19
|
+
returns: ['string memory'],
|
|
20
|
+
mutability: 'pure' as const,
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export function setClockMode(c: ContractBuilder, parent: ReferencedContract, votes: ClockMode) {
|
|
25
|
+
if (votes === 'timestamp') {
|
|
26
|
+
c.addOverride(parent, functions.clock);
|
|
27
|
+
c.setFunctionBody(['return uint48(block.timestamp);'], functions.clock);
|
|
28
|
+
|
|
29
|
+
c.setFunctionComments(['// solhint-disable-next-line func-name-mixedcase'], functions.CLOCK_MODE);
|
|
30
|
+
c.addOverride(parent, functions.CLOCK_MODE);
|
|
31
|
+
c.setFunctionBody(['return "mode=timestamp";'], functions.CLOCK_MODE);
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/test.ts
CHANGED
|
@@ -1,14 +1,42 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import _test, { TestFn, ExecutionContext } from 'ava';
|
|
2
3
|
import hre from 'hardhat';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
|
|
5
6
|
import { generateSources, writeGeneratedSources } from './generate/sources';
|
|
6
|
-
import type { GenericOptions } from './build-generic';
|
|
7
|
+
import type { GenericOptions, KindedOptions } from './build-generic';
|
|
7
8
|
import { custom, erc1155, erc20, erc721, governor } from './api';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
interface Context {
|
|
11
|
+
generatedSourcesPath: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const test = _test as TestFn<Context>;
|
|
15
|
+
|
|
16
|
+
test.serial('erc20 result compiles', async t => {
|
|
17
|
+
await testCompile(t, 'ERC20');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test.serial('erc721 result compiles', async t => {
|
|
21
|
+
await testCompile(t, 'ERC721');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test.serial('erc1155 result compiles', async t => {
|
|
25
|
+
await testCompile(t, 'ERC1155');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test.serial('governor result compiles', async t => {
|
|
29
|
+
await testCompile(t, 'Governor');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test.serial('custom result compiles', async t => {
|
|
33
|
+
await testCompile(t, 'Custom');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
async function testCompile(t: ExecutionContext<Context>, kind: keyof KindedOptions) {
|
|
37
|
+
const generatedSourcesPath = path.join(hre.config.paths.sources, `generated`);
|
|
38
|
+
await fs.rm(generatedSourcesPath, { force: true, recursive: true });
|
|
39
|
+
await writeGeneratedSources(generatedSourcesPath, 'all', kind);
|
|
12
40
|
|
|
13
41
|
// We only want to check that contracts compile and we don't care about any
|
|
14
42
|
// of the outputs. Setting empty outputSelection causes compilation to go a
|
|
@@ -19,7 +47,7 @@ test('result compiles', async t => {
|
|
|
19
47
|
|
|
20
48
|
await hre.run('compile');
|
|
21
49
|
t.pass();
|
|
22
|
-
}
|
|
50
|
+
}
|
|
23
51
|
|
|
24
52
|
function isAccessControlRequired(opts: GenericOptions) {
|
|
25
53
|
switch(opts.kind) {
|
package/src/utils/duration.ts
CHANGED
|
@@ -32,3 +32,21 @@ export function durationToBlocks(duration: string, blockTime: number): number {
|
|
|
32
32
|
const durationSeconds = value * secondsForUnit[unit];
|
|
33
33
|
return Math.round(durationSeconds / blockTime);
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
export function durationToTimestamp(duration: string): string {
|
|
37
|
+
const match = duration.trim().match(durationPattern);
|
|
38
|
+
|
|
39
|
+
if (!match) {
|
|
40
|
+
throw new Error('Bad duration format');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const value = match[1]!;
|
|
44
|
+
const unit = match[2]! as DurationUnit;
|
|
45
|
+
|
|
46
|
+
// unit must be a Solidity supported time unit
|
|
47
|
+
if (unit === 'block' || unit === 'month' || unit === 'year') {
|
|
48
|
+
throw new Error('Invalid unit for timestamp');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return `${value} ${unit}s`;
|
|
52
|
+
}
|