Skip to content

Commit acd866c

Browse files
committed
Revert "Revert "Cairo - Add Role-Based Access Control (#147)""
This reverts commit ea730c3.
1 parent 8c2d5ee commit acd866c

20 files changed

Lines changed: 1342 additions & 89 deletions

packages/core-cairo/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
},
3030
"dependencies": {
3131
"array.prototype.flatmap": "^1.2.4",
32-
"bn.js": "^5.2.0"
32+
"bn.js": "^5.2.0",
33+
"ethereum-cryptography": "^1.1.0"
3334
}
3435
}

packages/core-cairo/src/add-pausable.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export function addPausable(c: ContractBuilder, access: Access, pausableFns: Bas
1313

1414
c.addFunction(functions.paused);
1515

16-
requireAccessControl(c, functions.pause, access);
17-
requireAccessControl(c, functions.unpause, access);
16+
requireAccessControl(c, functions.pause, access, 'PAUSER');
17+
requireAccessControl(c, functions.unpause, access, 'PAUSER');
1818
}
1919

2020
const modules = defineModules( {
@@ -28,7 +28,7 @@ const functions = defineFunctions({
2828

2929
paused: {
3030
module: modules.Pausable,
31-
kind: 'view' as const,
31+
kind: 'view',
3232
implicitArgs: withImplicitArgs(),
3333
args: [],
3434
returns: [{ name: 'paused', type: 'felt' }],
@@ -38,15 +38,15 @@ const functions = defineFunctions({
3838

3939
pause: {
4040
module: modules.Pausable,
41-
kind: 'external' as const,
41+
kind: 'external',
4242
implicitArgs: withImplicitArgs(),
4343
args: [],
4444
parentFunctionName: '_pause',
4545
},
4646

4747
unpause: {
4848
module: modules.Pausable,
49-
kind: 'external' as const,
49+
kind: 'external',
5050
implicitArgs: withImplicitArgs(),
5151
args: [],
5252
parentFunctionName: '_unpause',

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import test from 'ava';
22

3-
import { ContractBuilder } from './contract';
3+
import { BaseFunction, ContractBuilder } from './contract';
44
import { printContract } from './print';
55

66
test('contract basics', t => {
@@ -49,15 +49,15 @@ const someModule = {
4949
useNamespace: true
5050
};
5151

52-
const _otherFunction = {
52+
const _otherFunction: BaseFunction = {
5353
name: 'otherFunction',
54-
kind: 'external' as const,
54+
kind: 'external',
5555
args: [],
5656
};
5757

58-
const _libraryFunction = {
58+
const _libraryFunction: BaseFunction = {
5959
module: someModule,
6060
name: 'libraryFunction',
61-
kind: 'external' as const,
61+
kind: 'external',
6262
args: [],
6363
};

packages/core-cairo/src/contract.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface Contract {
99
constructorCode: string[];
1010
constructorImplicitArgs?: Argument[];
1111
constructorArgs: Argument[];
12+
variables: string[];
1213
upgradeable: boolean;
1314
}
1415

@@ -44,11 +45,16 @@ export interface BaseFunction {
4445
}
4546

4647
export interface ContractFunction extends BaseFunction {
47-
libraryCalls: BaseFunction[];
48+
libraryCalls: LibraryCall[];
4849
code: string[];
4950
final: boolean;
5051
}
5152

53+
export interface LibraryCall {
54+
callFn: BaseFunction;
55+
args: string[];
56+
}
57+
5258
export type FunctionKind = 'view' | 'external';
5359

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

6874
readonly constructorArgs: Argument[] = [];
6975
readonly constructorCode: string[] = [];
76+
readonly variableSet: Set<string> = new Set();
7077

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

90+
get variables(): string[] {
91+
return [...this.variableSet];
92+
}
93+
8394
addModule(module: Module, params: Value[] = [], functions: BaseFunction[] = [], initializable: boolean = true): boolean {
8495
const key = module;
8596
const present = this.librariesMap.has(key);
@@ -116,15 +127,13 @@ export class ContractBuilder implements Contract {
116127
}
117128
}
118129

119-
addLibraryCall(callFn: BaseFunction, baseFn: BaseFunction) {
130+
addLibraryCall(callFn: BaseFunction, baseFn: BaseFunction, args: string[] = []) {
120131
const fn = this.addFunction(baseFn);
121132
if (callFn.module !== undefined) {
122133
this.addModuleFunction(callFn.module, getImportName(callFn));
123134
}
124-
if (callFn.args.length > 0) {
125-
throw new Error(`Library call with functions is not supported yet`);
126-
}
127-
fn.libraryCalls.push(callFn);
135+
const libraryCall: LibraryCall = { callFn, args };
136+
fn.libraryCalls.push(libraryCall);
128137
}
129138

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

190+
addVariable(code: string): boolean {
191+
const present = this.variableSet.has(code);
192+
this.variableSet.add(code);
193+
return !present;
194+
}
181195
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ testCustom('access control ownable', {
4242
access: 'ownable',
4343
});
4444

45+
testCustom('access control roles', {
46+
access: 'roles',
47+
});
48+
4549
testCustom('pausable with access control disabled', {
4650
// API should override access to true since it is required for pausable
4751
access: false,
@@ -51,7 +55,7 @@ testCustom('pausable with access control disabled', {
5155
testAPIEquivalence('custom API default');
5256

5357
testAPIEquivalence('custom API full upgradeable', {
54-
access: 'ownable',
58+
access: 'roles',
5559
pausable: true,
5660
upgradeable: true,
5761
});

packages/core-cairo/src/custom.test.ts.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,90 @@ Generated by [AVA](https://avajs.dev).
191191
end␊
192192
`
193193

194+
## access control roles
195+
196+
> Snapshot 1
197+
198+
`# SPDX-License-Identifier: MIT␊
199+
200+
%lang starknet␊
201+
202+
from starkware.cairo.common.cairo_builtins import HashBuiltin␊
203+
204+
from openzeppelin.access.accesscontrol import AccessControl␊
205+
from openzeppelin.utils.constants import DEFAULT_ADMIN_ROLE␊
206+
207+
@constructor␊
208+
func constructor{␊
209+
syscall_ptr: felt*,␊
210+
pedersen_ptr: HashBuiltin*,␊
211+
range_check_ptr␊
212+
}(admin: felt):␊
213+
AccessControl.initializer()␊
214+
215+
AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin)␊
216+
return ()␊
217+
end␊
218+
219+
#␊
220+
# Getters␊
221+
#␊
222+
223+
@view␊
224+
func hasRole{␊
225+
syscall_ptr: felt*,␊
226+
pedersen_ptr: HashBuiltin*,␊
227+
range_check_ptr␊
228+
}(role: felt, user: felt) -> (has_role: felt):␊
229+
let (has_role) = AccessControl.has_role(role, user)␊
230+
return (has_role)␊
231+
end␊
232+
233+
@view␊
234+
func getRoleAdmin{␊
235+
syscall_ptr: felt*,␊
236+
pedersen_ptr: HashBuiltin*,␊
237+
range_check_ptr␊
238+
}(role: felt) -> (admin: felt):␊
239+
let (admin) = AccessControl.get_role_admin(role)␊
240+
return (admin)␊
241+
end␊
242+
243+
#␊
244+
# Externals␊
245+
#␊
246+
247+
@external␊
248+
func grantRole{␊
249+
syscall_ptr: felt*,␊
250+
pedersen_ptr: HashBuiltin*,␊
251+
range_check_ptr␊
252+
}(role: felt, user: felt):␊
253+
AccessControl.grant_role(role, user)␊
254+
return ()␊
255+
end␊
256+
257+
@external␊
258+
func revokeRole{␊
259+
syscall_ptr: felt*,␊
260+
pedersen_ptr: HashBuiltin*,␊
261+
range_check_ptr␊
262+
}(role: felt, user: felt):␊
263+
AccessControl.revoke_role(role, user)␊
264+
return ()␊
265+
end␊
266+
267+
@external␊
268+
func renounceRole{␊
269+
syscall_ptr: felt*,␊
270+
pedersen_ptr: HashBuiltin*,␊
271+
range_check_ptr␊
272+
}(role: felt, user: felt):␊
273+
AccessControl.renounce_role(role, user)␊
274+
return ()␊
275+
end␊
276+
`
277+
194278
## pausable with access control disabled
195279

196280
> Snapshot 1
213 Bytes
Binary file not shown.

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ testERC20('erc20 pausable', {
4141
access: 'ownable',
4242
});
4343

44+
testERC20('erc20 pausable with roles', {
45+
pausable: true,
46+
access: 'roles',
47+
});
48+
4449
testERC20('erc20 burnable pausable', {
4550
burnable: true,
4651
pausable: true,
@@ -59,9 +64,25 @@ testERC20('erc20 mintable', {
5964
access: 'ownable',
6065
});
6166

67+
testERC20('erc20 mintable with roles', {
68+
mintable: true,
69+
access: 'roles',
70+
});
71+
6272
testERC20('erc20 full upgradeable', {
6373
premint: '2000',
6474
decimals: '9',
75+
access: 'ownable',
76+
burnable: true,
77+
mintable: true,
78+
pausable: true,
79+
upgradeable: true,
80+
});
81+
82+
testERC20('erc20 full upgradeable with roles', {
83+
premint: '2000',
84+
decimals: '9',
85+
access: 'roles',
6586
burnable: true,
6687
mintable: true,
6788
pausable: true,
@@ -77,6 +98,7 @@ testAPIEquivalence('erc20 API full upgradeable', {
7798
symbol: 'CTK',
7899
premint: '2000',
79100
decimals: '9',
101+
access: 'roles',
80102
burnable: true,
81103
mintable: true,
82104
pausable: true,

0 commit comments

Comments
 (0)