Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Governor #417

Merged
merged 22 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 138 additions & 18 deletions packages/core-cairo/src/account.test.ts.md

Large diffs are not rendered by default.

Binary file modified packages/core-cairo/src/account.test.ts.snap
Binary file not shown.
14 changes: 7 additions & 7 deletions packages/core-cairo/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function buildAccount(opts: AccountOptions): Contract {
c.addComponent(components.AccountComponent, [{ lit: 'public_key' }], true);
break;
case 'eth':
c.addStandaloneImport('openzeppelin::account::interface::EthPublicKey;');
c.addUseClause('openzeppelin::account::interface', 'EthPublicKey');
c.addConstructorArgument({ name: 'public_key', type: 'EthPublicKey' });
c.addComponent(components.EthAccountComponent, [{ lit: 'public_key' }], true);
break;
Expand Down Expand Up @@ -160,11 +160,11 @@ const components = defineComponents( {
name: 'AccountEvent',
type: 'AccountComponent::Event',
},
impls: [],
internalImpl: {
impls: [{
name: 'AccountInternalImpl',
embed: false,
value: 'AccountComponent::InternalImpl<ContractState>',
},
}],
},
EthAccountComponent: {
path: 'openzeppelin::account::eth_account',
Expand All @@ -176,10 +176,10 @@ const components = defineComponents( {
name: 'EthAccountEvent',
type: 'EthAccountComponent::Event',
},
impls: [],
internalImpl: {
impls: [{
name: 'EthAccountInternalImpl',
embed: false,
value: 'EthAccountComponent::InternalImpl<ContractState>',
},
}]
},
});
13 changes: 6 additions & 7 deletions packages/core-cairo/src/add-pausable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@ const components = defineComponents( {
name: 'PausableEvent',
type: 'PausableComponent::Event',
},
impls: [
{
impls: [{
name: 'PausableImpl',
value: 'PausableComponent::PausableImpl<ContractState>',
},
}, {
name: 'PausableInternalImpl',
embed: false,
value: 'PausableComponent::InternalImpl<ContractState>',
}
],
internalImpl: {
name: 'PausableInternalImpl',
value: 'PausableComponent::InternalImpl<ContractState>',
},
},
});

Expand Down
7 changes: 7 additions & 0 deletions packages/core-cairo/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { printERC20, defaults as erc20defaults, isAccessControlRequired as erc20
import { printERC721, defaults as erc721defaults, isAccessControlRequired as erc721IsAccessControlRequired, ERC721Options } from './erc721';
import { printERC1155, defaults as erc1155defaults, isAccessControlRequired as erc1155IsAccessControlRequired, ERC1155Options } from './erc1155';
import { printAccount, defaults as accountDefaults, AccountOptions } from './account';
import { printGovernor, defaults as governorDefaults, isAccessControlRequired as governorIsAccessControlRequired, GovernorOptions } from './governor';
import { printCustom, defaults as customDefaults, isAccessControlRequired as customIsAccessControlRequired, CustomOptions } from './custom';

export interface WizardAccountAPI<Options extends CommonOptions>{
Expand Down Expand Up @@ -39,6 +40,7 @@ export type ERC20 = WizardContractAPI<ERC20Options>;
export type ERC721 = WizardContractAPI<ERC721Options>;
export type ERC1155 = WizardContractAPI<ERC1155Options>;
export type Account = WizardAccountAPI<AccountOptions>;
export type Governor = WizardContractAPI<GovernorOptions>;
export type Custom = WizardContractAPI<CustomOptions>;

export const erc20: ERC20 = {
Expand All @@ -60,6 +62,11 @@ export const account: Account = {
print: printAccount,
defaults: accountDefaults,
}
export const governor: Governor = {
print: printGovernor,
defaults: governorDefaults,
isAccessControlRequired: governorIsAccessControlRequired
}
export const custom: Custom = {
print: printCustom,
defaults: customDefaults,
Expand Down
6 changes: 5 additions & 1 deletion packages/core-cairo/src/build-generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { ERC721Options, buildERC721 } from './erc721';
import { ERC1155Options, buildERC1155 } from './erc1155';
import { CustomOptions, buildCustom } from './custom';
import { AccountOptions, buildAccount } from './account';

import { GovernorOptions, buildGovernor } from './governor';
export interface KindedOptions {
ERC20: { kind: 'ERC20' } & ERC20Options;
ERC721: { kind: 'ERC721' } & ERC721Options;
ERC1155: { kind: 'ERC1155' } & ERC1155Options;
Account: { kind: 'Account' } & AccountOptions;
Governor: { kind: 'Governor' } & GovernorOptions;
Custom: { kind: 'Custom' } & CustomOptions;
}

Expand All @@ -28,6 +29,9 @@ export function buildGeneric(opts: GenericOptions) {
case 'Account':
return buildAccount(opts);

case 'Governor':
return buildGovernor(opts);

case 'Custom':
return buildCustom(opts);

Expand Down
18 changes: 12 additions & 6 deletions packages/core-cairo/src/common-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ const components = defineComponents( {
name: 'VotesEvent',
type: 'VotesComponent::Event',
},
impls: [],
internalImpl: {
impls: [{
name: 'VotesInternalImpl',
embed: false,
value: 'VotesComponent::InternalImpl<ContractState>',
},
}],
},

NoncesComponent: {
Expand All @@ -54,32 +54,38 @@ const components = defineComponents( {
},
})

export function addSRC5Component(c: ContractBuilder) {
export function addSRC5Component(c: ContractBuilder, section?: string) {
c.addComponent(components.SRC5Component, [], false);

if (!c.interfaceFlags.has('ISRC5')) {
c.addImplToComponent(components.SRC5Component, {
name: 'SRC5Impl',
value: 'SRC5Component::SRC5Impl<ContractState>',
section,
});
c.addInterfaceFlag('ISRC5');
}
}

export function addVotesComponent(c: ContractBuilder, name: string, version: string) {
c.addStandaloneImport('openzeppelin::utils::cryptography::snip12::SNIP12Metadata');
export function addVotesComponent(c: ContractBuilder, name: string, version: string, section?: string) {
addSNIP12Metadata(c, name, version, section);
c.addComponent(components.NoncesComponent, [], false);
c.addComponent(components.VotesComponent, [], false);
c.addImplToComponent(components.VotesComponent, {
name: 'VotesImpl',
value: `VotesComponent::VotesImpl<ContractState>`,
});
}

export function addSNIP12Metadata(c: ContractBuilder, name: string, version: string, section?: string) {
c.addUseClause('openzeppelin::utils::cryptography::snip12', 'SNIP12Metadata');

const SNIP12Metadata: BaseImplementedTrait = {
name: 'SNIP12MetadataImpl',
of: 'SNIP12Metadata',
tags: [],
priority: 0,
section,
};
c.addImplementedTrait(SNIP12Metadata);

Expand Down
16 changes: 8 additions & 8 deletions packages/core-cairo/src/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@ const FOO_COMPONENT: Component = {
name: 'FooEvent',
type: 'FooComponent::Event',
},
impls: [
{
impls: [{
name: 'FooImpl',
value: 'FooComponent::FooImpl<ContractState>',
},
}, {
name: 'FooInternalImpl',
embed: false,
value: 'FooComponent::InternalImpl<ContractState>',
}
],
internalImpl: {
name: 'FooInternalImpl',
value: 'FooComponent::InternalImpl<ContractState>',
},
};

test('contract basics', t => {
Expand Down Expand Up @@ -107,6 +106,7 @@ test('contract with standalone import', t => {
Foo.addComponent(
FOO_COMPONENT,
);
Foo.addStandaloneImport('some::library::SomeLibrary');
Foo.addUseClause('some::library', 'SomeLibrary');
t.snapshot(printContract(Foo));
});

9 changes: 9 additions & 0 deletions packages/core-cairo/src/contract.test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,11 @@ Generated by [AVA](https://avajs.dev).
component!(path: FooComponent, storage: foo, event: FooEvent);␊
// External␊
#[abi(embed_v0)]␊
impl FooImpl = FooComponent::FooImpl<ContractState>;␊
// Internal␊
impl FooInternalImpl = FooComponent::InternalImpl<ContractState>;␊
#[storage]␊
Expand Down Expand Up @@ -161,9 +163,11 @@ Generated by [AVA](https://avajs.dev).
component!(path: FooComponent, storage: foo, event: FooEvent);␊
// External␊
#[abi(embed_v0)]␊
impl FooImpl = FooComponent::FooImpl<ContractState>;␊
// Internal␊
impl FooInternalImpl = FooComponent::InternalImpl<ContractState>;␊
#[storage]␊
Expand All @@ -178,5 +182,10 @@ Generated by [AVA](https://avajs.dev).
#[flat]␊
FooEvent: FooComponent::Event,␊
}␊
#[constructor]␊
fn constructor(ref self: ContractState) {␊
self.foo.initializer();␊
}␊
}␊
`
Binary file modified packages/core-cairo/src/contract.test.ts.snap
Binary file not shown.
55 changes: 46 additions & 9 deletions packages/core-cairo/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ export interface Contract {
license: string;
name: string;
account: boolean;
standaloneImports: string[];
useClauses: UseClause[];
components: Component[];
constants: Variable[];
constructorCode: string[];
constructorArgs: Argument[];
upgradeable: boolean;
Expand All @@ -15,13 +16,19 @@ export interface Contract {

export type Value = string | number | bigint | { lit: string } | { note: string, value: Value };

export interface UseClause {
containerPath: string;
name: string;
groupable?: boolean;
alias?: string;
}

export interface Component {
name: string;
path: string;
substorage: Substorage;
event: Event;
impls: Impl[];
internalImpl?: Impl;
initializer?: Initializer;
}

Expand All @@ -38,6 +45,8 @@ export interface Event {
export interface Impl {
name: string;
value: string;
embed?: boolean;
section?: string;
}

export interface Initializer {
Expand All @@ -49,6 +58,7 @@ export interface BaseImplementedTrait {
of: string;
tags: string[];
perItemTag?: string;
section?: string;
/**
* Priority for which trait to print first.
* Lower numbers are higher priority, undefined is lowest priority.
Expand All @@ -59,6 +69,7 @@ export interface BaseImplementedTrait {
export interface ImplementedTrait extends BaseImplementedTrait {
superVariables: Variable[];
functions: ContractFunction[];
section?: string;
}

export interface BaseFunction {
Expand All @@ -77,6 +88,8 @@ export interface Variable {
name: string;
type: string;
value: string;
comment?: string;
inlineComment?: boolean;
}

export interface Argument {
Expand All @@ -96,7 +109,8 @@ export class ContractBuilder implements Contract {
private componentsMap: Map<string, Component> = new Map();
private implementedTraitsMap: Map<string, ImplementedTrait> = new Map();
private superVariablesMap: Map<string, Variable> = new Map();
private standaloneImportsSet: Set<string> = new Set();
private constantsMap: Map<string, Variable> = new Map();
private useClausesMap: Map<string, UseClause> = new Map();
private interfaceFlagsSet: Set<string> = new Set();

constructor(name: string, account: boolean = false) {
Expand All @@ -116,8 +130,12 @@ export class ContractBuilder implements Contract {
return [...this.superVariablesMap.values()];
}

get standaloneImports(): string[] {
return [...this.standaloneImportsSet];
get constants(): Variable[] {
return [...this.constantsMap.values()];
}

get useClauses(): UseClause[] {
return [...this.useClausesMap.values()];
}

/**
Expand All @@ -127,11 +145,19 @@ export class ContractBuilder implements Contract {
return this.interfaceFlagsSet;
}

addStandaloneImport(fullyQualified: string): void {
this.standaloneImportsSet.add(fullyQualified);
addUseClause(containerPath: string, name: string, options?: { groupable?: boolean, alias?: string }): void {
// groupable defaults to true
const groupable = options?.groupable ?? true;
const alias = options?.alias ?? '';
const uniqueName = alias.length > 0 ? alias : name;
const present = this.useClausesMap.has(uniqueName);
if (!present) {
this.useClausesMap.set(uniqueName, { containerPath, name, groupable, alias });
}
}

addComponent(component: Component, params: Value[] = [], initializable: boolean = true): boolean {
this.addUseClause(component.path, component.name);
const key = component.name;
const present = this.componentsMap.has(key);
if (!present) {
Expand All @@ -144,7 +170,7 @@ export class ContractBuilder implements Contract {

addImplToComponent(component: Component, impl: Impl): void {
this.addComponent(component);
let c = this.componentsMap.get(component.name);
const c = this.componentsMap.get(component.name);
if (c == undefined) {
throw new Error(`Component ${component.name} has not been added yet`);
}
Expand All @@ -154,11 +180,21 @@ export class ContractBuilder implements Contract {
}
}

addConstant(constant: Variable): boolean {
if (this.constantsMap.has(constant.name)) {
return false;
} else {
this.constantsMap.set(constant.name, constant);
return true;
}
}

addSuperVariable(variable: Variable): boolean {
if (this.superVariablesMap.has(variable.name)) {
return false;
} else {
this.superVariablesMap.set(variable.name, variable);
this.addUseClause('super', variable.name);
return true;
}
}
Expand All @@ -169,12 +205,13 @@ export class ContractBuilder implements Contract {
if (existingTrait !== undefined) {
return existingTrait;
} else {
const t: ImplementedTrait = {
const t: ImplementedTrait = {
name: baseTrait.name,
of: baseTrait.of,
tags: [ ...baseTrait.tags ],
superVariables: [],
functions: [],
section: baseTrait.section,
priority: baseTrait.priority,
};
this.implementedTraitsMap.set(key, t);
Expand Down
Loading
Loading