Skip to content

Commit e08725a

Browse files
immrsdericglau
andauthored
Add Vesting (#425)
Co-authored-by: Eric Lau <[email protected]>
1 parent f0a4438 commit e08725a

20 files changed

+888
-22
lines changed

packages/core-cairo/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Changelog
22

3-
## Unreleased
3+
## 0.21.0 (2025-01-09)
44

5+
- Add Vesting tab. ([#425](https://github.com/OpenZeppelin/contracts-wizard/pull/425))
56
- Update Contracts Wizard license to AGPLv3. ([#424](https://github.com/OpenZeppelin/contracts-wizard/pull/424))
67

78
## 0.20.1 (2024-12-17)

packages/core-cairo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openzeppelin/wizard-cairo",
3-
"version": "0.20.1",
3+
"version": "0.21.0",
44
"description": "A boilerplate generator to get started with OpenZeppelin Contracts for Cairo",
55
"license": "AGPL-3.0-only",
66
"repository": "https://github.com/OpenZeppelin/contracts-wizard",

packages/core-cairo/src/api.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { printERC1155, defaults as erc1155defaults, isAccessControlRequired as e
55
import { printAccount, defaults as accountDefaults, AccountOptions } from './account';
66
import { printGovernor, defaults as governorDefaults, isAccessControlRequired as governorIsAccessControlRequired, GovernorOptions } from './governor';
77
import { printCustom, defaults as customDefaults, isAccessControlRequired as customIsAccessControlRequired, CustomOptions } from './custom';
8+
import { printVesting, defaults as vestingDefaults, isAccessControlRequired as vestingIsAccessControlRequired, VestingOptions } from './vesting';
89

910
export interface WizardAccountAPI<Options extends CommonOptions>{
1011
/**
@@ -41,6 +42,7 @@ export type ERC721 = WizardContractAPI<ERC721Options>;
4142
export type ERC1155 = WizardContractAPI<ERC1155Options>;
4243
export type Account = WizardAccountAPI<AccountOptions>;
4344
export type Governor = WizardContractAPI<GovernorOptions>;
45+
export type Vesting = WizardContractAPI<VestingOptions>;
4446
export type Custom = WizardContractAPI<CustomOptions>;
4547

4648
export const erc20: ERC20 = {
@@ -67,6 +69,11 @@ export const governor: Governor = {
6769
defaults: governorDefaults,
6870
isAccessControlRequired: governorIsAccessControlRequired
6971
}
72+
export const vesting: Vesting = {
73+
print: printVesting,
74+
defaults: vestingDefaults,
75+
isAccessControlRequired: vestingIsAccessControlRequired
76+
}
7077
export const custom: Custom = {
7178
print: printCustom,
7279
defaults: customDefaults,

packages/core-cairo/src/build-generic.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import { ERC1155Options, buildERC1155 } from './erc1155';
44
import { CustomOptions, buildCustom } from './custom';
55
import { AccountOptions, buildAccount } from './account';
66
import { GovernorOptions, buildGovernor } from './governor';
7+
import { VestingOptions, buildVesting } from './vesting';
8+
79
export interface KindedOptions {
810
ERC20: { kind: 'ERC20' } & ERC20Options;
911
ERC721: { kind: 'ERC721' } & ERC721Options;
1012
ERC1155: { kind: 'ERC1155' } & ERC1155Options;
1113
Account: { kind: 'Account' } & AccountOptions;
1214
Governor: { kind: 'Governor' } & GovernorOptions;
15+
Vesting: { kind: 'Vesting' } & VestingOptions;
1316
Custom: { kind: 'Custom' } & CustomOptions;
1417
}
1518

@@ -32,6 +35,9 @@ export function buildGeneric(opts: GenericOptions) {
3235
case 'Governor':
3336
return buildGovernor(opts);
3437

38+
case 'Vesting':
39+
return buildVesting(opts);
40+
3541
case 'Custom':
3642
return buildCustom(opts);
3743

packages/core-cairo/src/generate/sources.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { generateERC1155Options } from './erc1155';
88
import { generateAccountOptions } from './account';
99
import { generateCustomOptions } from './custom';
1010
import { generateGovernorOptions } from './governor';
11+
import { generateVestingOptions } from './vesting';
1112
import { buildGeneric, GenericOptions, KindedOptions } from '../build-generic';
1213
import { printContract } from '../print';
1314
import { OptionsError } from '../error';
@@ -54,6 +55,12 @@ export function* generateOptions(kind?: Kind): Generator<GenericOptions> {
5455
yield { kind: 'Governor', ...kindOpts };
5556
}
5657
}
58+
59+
if (!kind || kind === 'Vesting') {
60+
for (const kindOpts of generateVestingOptions()) {
61+
yield { kind: 'Vesting', ...kindOpts };
62+
}
63+
}
5764
}
5865

5966
interface GeneratedContract {
@@ -92,9 +99,27 @@ function generateContractSubset(subset: Subset, kind?: Kind): GeneratedContract[
9299
return contracts;
93100
} else {
94101
const getParents = (c: GeneratedContract) => c.contract.components.map(p => p.path);
102+
function filterByUpgradeableSetTo(isUpgradeable: boolean) {
103+
return (c: GeneratedContract) => {
104+
switch (c.options.kind) {
105+
case 'Vesting':
106+
return isUpgradeable === false;
107+
case 'Account':
108+
case 'ERC20':
109+
case 'ERC721':
110+
case 'ERC1155':
111+
case 'Governor':
112+
case 'Custom':
113+
return c.options.upgradeable === isUpgradeable;
114+
default:
115+
const _: never = c.options;
116+
throw new Error('Unknown kind');
117+
}
118+
}
119+
}
95120
return [
96-
...findCover(contracts.filter(c => c.options.upgradeable), getParents),
97-
...findCover(contracts.filter(c => !c.options.upgradeable), getParents),
121+
...findCover(contracts.filter(filterByUpgradeableSetTo(true)), getParents),
122+
...findCover(contracts.filter(filterByUpgradeableSetTo(false)), getParents),
98123
];
99124
}
100125
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { infoOptions } from '../set-info';
2+
import type { VestingOptions } from '../vesting';
3+
import { generateAlternatives } from './alternatives';
4+
5+
const blueprint = {
6+
name: ['MyVesting'],
7+
startDate: ['2024-12-31T23:59'],
8+
duration: ['90 days', '1 year'],
9+
cliffDuration: ['0 seconds', '30 day'],
10+
schedule: ['linear', 'custom'] as const,
11+
info: infoOptions
12+
};
13+
14+
export function* generateVestingOptions(): Generator<Required<VestingOptions>> {
15+
yield* generateAlternatives(blueprint);
16+
}

packages/core-cairo/src/governor.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ testAPIEquivalence('API erc721 votes + timelock', {
125125
});
126126

127127
testAPIEquivalence('API custom name', {
128+
name: 'CustomGovernor',
128129
delay: '1 day',
129130
period: '1 week',
130-
name: 'CustomGovernor',
131131
});
132132

133133
testAPIEquivalence('API custom settings', {
@@ -146,7 +146,8 @@ testAPIEquivalence('API quorum mode absolute', {
146146
quorumAbsolute: '200',
147147
});
148148

149-
testAPIEquivalence('API quorum mode percent', { name: NAME,
149+
testAPIEquivalence('API quorum mode percent', {
150+
name: NAME,
150151
delay: '1 day',
151152
period: '1 week',
152153
quorumMode: 'percent',

packages/core-cairo/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ export { sanitizeKind } from './kind';
2525

2626
export { contractsVersion, contractsVersionTag, compatibleContractsSemver } from './utils/version';
2727

28-
export { erc20, erc721, erc1155, account, governor, custom } from './api';
28+
export { erc20, erc721, erc1155, account, governor, vesting, custom } from './api';

packages/core-cairo/src/kind.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ function isKind<T>(value: Kind | T): value is Kind {
1919
case 'ERC1155':
2020
case 'Account':
2121
case 'Governor':
22+
case 'Vesting':
2223
case 'Custom':
2324
return true;
2425

packages/core-cairo/src/set-upgradeable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export type Upgradeable = typeof upgradeableOptions[number];
1111

1212
function setUpgradeableBase(c: ContractBuilder, upgradeable: Upgradeable): BaseImplementedTrait | undefined {
1313
if (upgradeable === false) {
14-
return;
14+
return undefined;
1515
}
1616

1717
c.upgradeable = true;

0 commit comments

Comments
 (0)