Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions packages/core-cairo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

- Add Role-Based Access Control. ([#147](https://github.com/OpenZeppelin/contracts-wizard/pull/147))

## 0.3.0 (2022-07-01)

- Support Contracts for Cairo v0.2.0. ([#135](https://github.com/OpenZeppelin/contracts-wizard/pull/135))
Expand Down
3 changes: 2 additions & 1 deletion packages/core-cairo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
},
"dependencies": {
"array.prototype.flatmap": "^1.2.4",
"bn.js": "^5.2.0"
"bn.js": "^5.2.0",
"ethereum-cryptography": "^1.1.0"
}
}
10 changes: 5 additions & 5 deletions packages/core-cairo/src/add-pausable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export function addPausable(c: ContractBuilder, access: Access, pausableFns: Bas

c.addFunction(functions.paused);

requireAccessControl(c, functions.pause, access);
requireAccessControl(c, functions.unpause, access);
requireAccessControl(c, functions.pause, access, 'PAUSER');
requireAccessControl(c, functions.unpause, access, 'PAUSER');
}

const modules = defineModules( {
Expand All @@ -28,7 +28,7 @@ const functions = defineFunctions({

paused: {
module: modules.Pausable,
kind: 'view' as const,
kind: 'view',
implicitArgs: withImplicitArgs(),
args: [],
returns: [{ name: 'paused', type: 'felt' }],
Expand All @@ -38,15 +38,15 @@ const functions = defineFunctions({

pause: {
module: modules.Pausable,
kind: 'external' as const,
kind: 'external',
implicitArgs: withImplicitArgs(),
args: [],
parentFunctionName: '_pause',
},

unpause: {
module: modules.Pausable,
kind: 'external' as const,
kind: 'external',
implicitArgs: withImplicitArgs(),
args: [],
parentFunctionName: '_unpause',
Expand Down
10 changes: 5 additions & 5 deletions packages/core-cairo/src/contract.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import test from 'ava';

import { ContractBuilder } from './contract';
import { BaseFunction, ContractBuilder } from './contract';
import { printContract } from './print';

test('contract basics', t => {
Expand Down Expand Up @@ -49,15 +49,15 @@ const someModule = {
useNamespace: true
};

const _otherFunction = {
const _otherFunction: BaseFunction = {
name: 'otherFunction',
kind: 'external' as const,
kind: 'external',
args: [],
};

const _libraryFunction = {
const _libraryFunction: BaseFunction = {
module: someModule,
name: 'libraryFunction',
kind: 'external' as const,
kind: 'external',
args: [],
};
26 changes: 20 additions & 6 deletions packages/core-cairo/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface Contract {
constructorCode: string[];
constructorImplicitArgs?: Argument[];
constructorArgs: Argument[];
variables: string[];
upgradeable: boolean;
}

Expand Down Expand Up @@ -44,11 +45,16 @@ export interface BaseFunction {
}

export interface ContractFunction extends BaseFunction {
libraryCalls: BaseFunction[];
libraryCalls: LibraryCall[];
code: string[];
final: boolean;
}

export interface LibraryCall {
callFn: BaseFunction;
args: string[];
}

export type FunctionKind = 'view' | 'external';

export interface Argument {
Expand All @@ -67,6 +73,7 @@ export class ContractBuilder implements Contract {

readonly constructorArgs: Argument[] = [];
readonly constructorCode: string[] = [];
readonly variableSet: Set<string> = new Set();

private librariesMap: Map<Module, Library> = new Map<Module, Library>();
private functionMap: Map<string, ContractFunction> = new Map();
Expand All @@ -80,6 +87,10 @@ export class ContractBuilder implements Contract {
return [...this.functionMap.values()];
}

get variables(): string[] {
return [...this.variableSet];
}

addModule(module: Module, params: Value[] = [], functions: BaseFunction[] = [], initializable: boolean = true): boolean {
const key = module;
const present = this.librariesMap.has(key);
Expand Down Expand Up @@ -116,15 +127,13 @@ export class ContractBuilder implements Contract {
}
}

addLibraryCall(callFn: BaseFunction, baseFn: BaseFunction) {
addLibraryCall(callFn: BaseFunction, baseFn: BaseFunction, args: string[] = []) {
const fn = this.addFunction(baseFn);
if (callFn.module !== undefined) {
this.addModuleFunction(callFn.module, getImportName(callFn));
}
if (callFn.args.length > 0) {
throw new Error(`Library call with functions is not supported yet`);
}
fn.libraryCalls.push(callFn);
const libraryCall: LibraryCall = { callFn, args };
fn.libraryCalls.push(libraryCall);
}

addFunction(baseFn: BaseFunction): ContractFunction {
Expand Down Expand Up @@ -178,4 +187,9 @@ export class ContractBuilder implements Contract {
fn.final = true;
}

addVariable(code: string): boolean {
const present = this.variableSet.has(code);
this.variableSet.add(code);
return !present;
}
}
6 changes: 5 additions & 1 deletion packages/core-cairo/src/custom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ testCustom('access control ownable', {
access: 'ownable',
});

testCustom('access control roles', {
access: 'roles',
});

testCustom('pausable with access control disabled', {
// API should override access to true since it is required for pausable
access: false,
Expand All @@ -51,7 +55,7 @@ testCustom('pausable with access control disabled', {
testAPIEquivalence('custom API default');

testAPIEquivalence('custom API full upgradeable', {
access: 'ownable',
access: 'roles',
pausable: true,
upgradeable: true,
});
Expand Down
84 changes: 84 additions & 0 deletions packages/core-cairo/src/custom.test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,90 @@ Generated by [AVA](https://avajs.dev).
end␊
`

## access control roles

> Snapshot 1

`# SPDX-License-Identifier: MIT␊
%lang starknet␊
from starkware.cairo.common.cairo_builtins import HashBuiltin␊
from openzeppelin.access.accesscontrol import AccessControl␊
from openzeppelin.utils.constants import DEFAULT_ADMIN_ROLE␊
@constructor␊
func constructor{␊
syscall_ptr: felt*,␊
pedersen_ptr: HashBuiltin*,␊
range_check_ptr␊
}(admin: felt):␊
AccessControl.initializer()␊
AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin)␊
return ()␊
end␊
#␊
# Getters␊
#␊
@view␊
func hasRole{␊
syscall_ptr: felt*,␊
pedersen_ptr: HashBuiltin*,␊
range_check_ptr␊
}(role: felt, user: felt) -> (has_role: felt):␊
let (has_role) = AccessControl.has_role(role, user)␊
return (has_role)␊
end␊
@view␊
func getRoleAdmin{␊
syscall_ptr: felt*,␊
pedersen_ptr: HashBuiltin*,␊
range_check_ptr␊
}(role: felt) -> (admin: felt):␊
let (admin) = AccessControl.get_role_admin(role)␊
return (admin)␊
end␊
#␊
# Externals␊
#␊
@external␊
func grantRole{␊
syscall_ptr: felt*,␊
pedersen_ptr: HashBuiltin*,␊
range_check_ptr␊
}(role: felt, user: felt):␊
AccessControl.grant_role(role, user)␊
return ()␊
end␊
@external␊
func revokeRole{␊
syscall_ptr: felt*,␊
pedersen_ptr: HashBuiltin*,␊
range_check_ptr␊
}(role: felt, user: felt):␊
AccessControl.revoke_role(role, user)␊
return ()␊
end␊
@external␊
func renounceRole{␊
syscall_ptr: felt*,␊
pedersen_ptr: HashBuiltin*,␊
range_check_ptr␊
}(role: felt, user: felt):␊
AccessControl.renounce_role(role, user)␊
return ()␊
end␊
`

## pausable with access control disabled

> Snapshot 1
Expand Down
Binary file modified packages/core-cairo/src/custom.test.ts.snap
Binary file not shown.
22 changes: 22 additions & 0 deletions packages/core-cairo/src/erc20.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ testERC20('erc20 pausable', {
access: 'ownable',
});

testERC20('erc20 pausable with roles', {
pausable: true,
access: 'roles',
});

testERC20('erc20 burnable pausable', {
burnable: true,
pausable: true,
Expand All @@ -59,9 +64,25 @@ testERC20('erc20 mintable', {
access: 'ownable',
});

testERC20('erc20 mintable with roles', {
mintable: true,
access: 'roles',
});

testERC20('erc20 full upgradeable', {
premint: '2000',
decimals: '9',
access: 'ownable',
burnable: true,
mintable: true,
pausable: true,
upgradeable: true,
});

testERC20('erc20 full upgradeable with roles', {
premint: '2000',
decimals: '9',
access: 'roles',
burnable: true,
mintable: true,
pausable: true,
Expand All @@ -77,6 +98,7 @@ testAPIEquivalence('erc20 API full upgradeable', {
symbol: 'CTK',
premint: '2000',
decimals: '9',
access: 'roles',
burnable: true,
mintable: true,
pausable: true,
Expand Down
Loading