or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

access-control.mdcontract-presets.mdcryptography-math.mdgsn-support.mdindex.mdintrospection.mdpayment-mechanisms.mdproxy-patterns.mdsecurity-utilities.mdtoken-standards.md

access-control.mddocs/

0

# Access Control

1

2

OpenZeppelin provides flexible access control mechanisms including simple ownership patterns and sophisticated role-based access control. These contracts enable secure management of administrative functions and permissions in smart contracts.

3

4

## Capabilities

5

6

### Ownable - Simple Ownership

7

8

Basic access control mechanism where there is an account (an owner) that can be granted exclusive access to specific functions.

9

10

```solidity { .api }

11

/**

12

* Contract module which provides a basic access control mechanism, where there is an account (an owner)

13

* that can be granted exclusive access to specific functions

14

*/

15

abstract contract Ownable is Context {

16

/**

17

* Returns the address of the current owner

18

*/

19

function owner() public view virtual returns (address);

20

21

/**

22

* Leaves the contract without owner. It will not be possible to call onlyOwner functions anymore

23

* Can only be called by the current owner

24

*/

25

function renounceOwnership() public virtual onlyOwner;

26

27

/**

28

* Transfers ownership of the contract to a new account (newOwner)

29

* Can only be called by the current owner

30

*/

31

function transferOwnership(address newOwner) public virtual onlyOwner;

32

33

/**

34

* Throws if called by any account other than the owner

35

*/

36

modifier onlyOwner();

37

38

/**

39

* Emitted when ownership is transferred

40

*/

41

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

42

}

43

```

44

45

**Usage Example:**

46

47

```solidity

48

import "@openzeppelin/contracts/access/Ownable.sol";

49

50

contract MyContract is Ownable {

51

uint256 private _value;

52

53

function setValue(uint256 newValue) public onlyOwner {

54

_value = newValue;

55

}

56

57

function getValue() public view returns (uint256) {

58

return _value;

59

}

60

}

61

```

62

63

### AccessControl - Role-Based Access Control

64

65

Role-based access control mechanism with hierarchical roles where each role can have multiple members and each role can have an admin role that can grant and revoke that role.

66

67

```solidity { .api }

68

/**

69

* Contract module that allows children to implement role-based access control mechanisms

70

*/

71

abstract contract AccessControl is Context, IAccessControl, ERC165 {

72

/**

73

* Default admin role for all roles. Only accounts with this role will be able to grant or revoke other roles

74

*/

75

bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

76

77

/**

78

* Returns true if account has been granted role

79

*/

80

function hasRole(bytes32 role, address account) public view virtual override returns (bool);

81

82

/**

83

* Returns the number of accounts that have role

84

*/

85

function getRoleMemberCount(bytes32 role) public view returns (uint256);

86

87

/**

88

* Returns one of the accounts that have role

89

*/

90

function getRoleMember(bytes32 role, uint256 index) public view returns (address);

91

92

/**

93

* Returns the admin role that controls role

94

*/

95

function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32);

96

97

/**

98

* Grants role to account

99

* If account had not been already granted role, emits a RoleGranted event

100

*/

101

function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role));

102

103

/**

104

* Revokes role from account

105

* If account had been granted role, emits a RoleRevoked event

106

*/

107

function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role));

108

109

/**

110

* Revokes role from the calling account

111

*/

112

function renounceRole(bytes32 role, address account) public virtual override;

113

114

/**

115

* Modifier that checks that an account has a specific role

116

*/

117

modifier onlyRole(bytes32 role);

118

119

/**

120

* Emitted when newAdminRole is set as role's admin role, replacing previousAdminRole

121

*/

122

event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

123

124

/**

125

* Emitted when account is granted role

126

*/

127

event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

128

129

/**

130

* Emitted when account is revoked role

131

*/

132

event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

133

}

134

```

135

136

**Usage Example:**

137

138

```solidity

139

import "@openzeppelin/contracts/access/AccessControl.sol";

140

141

contract MyContract is AccessControl {

142

bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

143

bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");

144

145

constructor() {

146

// Grant the contract deployer the default admin role

147

_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);

148

_grantRole(MINTER_ROLE, msg.sender);

149

}

150

151

function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {

152

// Mint tokens

153

}

154

155

function burn(uint256 amount) public onlyRole(BURNER_ROLE) {

156

// Burn tokens

157

}

158

}

159

```

160

161

### TimelockController - Delayed Execution

162

163

A timelock controller contract that acts as a timelocked admin. It is meant to be used with other contracts through composition.

164

165

```solidity { .api }

166

/**

167

* Contract module which acts as a timelocked controller

168

*/

169

contract TimelockController is AccessControl {

170

bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE");

171

bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");

172

bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");

173

174

/**

175

* Returns whether an id corresponds to a registered operation

176

*/

177

function isOperation(bytes32 id) public view virtual returns (bool registered);

178

179

/**

180

* Returns whether an operation is pending or not

181

*/

182

function isOperationPending(bytes32 id) public view virtual returns (bool pending);

183

184

/**

185

* Returns whether an operation is ready or not

186

*/

187

function isOperationReady(bytes32 id) public view virtual returns (bool ready);

188

189

/**

190

* Returns whether an operation is done or not

191

*/

192

function isOperationDone(bytes32 id) public view virtual returns (bool done);

193

194

/**

195

* Returns the timestamp at which an operation becomes ready

196

*/

197

function getTimestamp(bytes32 id) public view virtual returns (uint256 timestamp);

198

199

/**

200

* Returns the minimum delay for operations

201

*/

202

function getMinDelay() public view virtual returns (uint256 duration);

203

204

/**

205

* Returns the identifier of an operation containing a single transaction

206

*/

207

function hashOperation(

208

address target,

209

uint256 value,

210

bytes calldata data,

211

bytes32 predecessor,

212

bytes32 salt

213

) public pure virtual returns (bytes32 hash);

214

215

/**

216

* Returns the identifier of an operation containing a batch of transactions

217

*/

218

function hashOperationBatch(

219

address[] calldata targets,

220

uint256[] calldata values,

221

bytes[] calldata datas,

222

bytes32 predecessor,

223

bytes32 salt

224

) public pure virtual returns (bytes32 hash);

225

226

/**

227

* Schedule an operation containing a single transaction

228

*/

229

function schedule(

230

address target,

231

uint256 value,

232

bytes calldata data,

233

bytes32 predecessor,

234

bytes32 salt,

235

uint256 delay

236

) public virtual onlyRole(PROPOSER_ROLE);

237

238

/**

239

* Schedule an operation containing a batch of transactions

240

*/

241

function scheduleBatch(

242

address[] calldata targets,

243

uint256[] calldata values,

244

bytes[] calldata datas,

245

bytes32 predecessor,

246

bytes32 salt,

247

uint256 delay

248

) public virtual onlyRole(PROPOSER_ROLE);

249

250

/**

251

* Cancel an operation

252

*/

253

function cancel(bytes32 id) public virtual onlyRole(PROPOSER_ROLE);

254

255

/**

256

* Execute an (ready) operation containing a single transaction

257

*/

258

function execute(

259

address target,

260

uint256 value,

261

bytes calldata data,

262

bytes32 predecessor,

263

bytes32 salt

264

) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE);

265

266

/**

267

* Execute an (ready) operation containing a batch of transactions

268

*/

269

function executeBatch(

270

address[] calldata targets,

271

uint256[] calldata values,

272

bytes[] calldata datas,

273

bytes32 predecessor,

274

bytes32 salt

275

) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE);

276

277

/**

278

* Changes the minimum timelock duration for future operations

279

*/

280

function updateDelay(uint256 newDelay) external virtual;

281

282

event CallScheduled(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data, bytes32 predecessor, uint256 delay);

283

event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);

284

event Cancelled(bytes32 indexed id);

285

event MinDelayChange(uint256 oldDuration, uint256 newDuration);

286

}

287

```

288

289

## Access Control Patterns

290

291

### Combining Ownership and Roles

292

293

```solidity

294

import "@openzeppelin/contracts/access/Ownable.sol";

295

import "@openzeppelin/contracts/access/AccessControl.sol";

296

297

contract MyContract is Ownable, AccessControl {

298

bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");

299

300

constructor() {

301

_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);

302

}

303

304

// Only owner can add operators

305

function addOperator(address operator) public onlyOwner {

306

grantRole(OPERATOR_ROLE, operator);

307

}

308

309

// Only operators can perform this action

310

function performOperation() public onlyRole(OPERATOR_ROLE) {

311

// Operation logic

312

}

313

314

// Override required by Solidity for multiple inheritance

315

function supportsInterface(bytes4 interfaceId)

316

public view override(AccessControl) returns (bool) {

317

return super.supportsInterface(interfaceId);

318

}

319

}

320

```

321

322

### Multi-Signature with AccessControl

323

324

```solidity

325

import "@openzeppelin/contracts/access/AccessControl.sol";

326

327

contract MultiSigContract is AccessControl {

328

bytes32 public constant SIGNER_ROLE = keccak256("SIGNER_ROLE");

329

330

uint256 public constant REQUIRED_SIGNATURES = 2;

331

mapping(bytes32 => uint256) public proposalSignatures;

332

mapping(bytes32 => mapping(address => bool)) public hasSignedProposal;

333

334

constructor(address[] memory signers) {

335

_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);

336

for (uint i = 0; i < signers.length; i++) {

337

_grantRole(SIGNER_ROLE, signers[i]);

338

}

339

}

340

341

function signProposal(bytes32 proposalId) public onlyRole(SIGNER_ROLE) {

342

require(!hasSignedProposal[proposalId][msg.sender], "Already signed");

343

hasSignedProposal[proposalId][msg.sender] = true;

344

proposalSignatures[proposalId]++;

345

}

346

347

function executeProposal(bytes32 proposalId) public {

348

require(proposalSignatures[proposalId] >= REQUIRED_SIGNATURES, "Insufficient signatures");

349

// Execute proposal logic

350

}

351

}

352

```

353

354

### Timelock Integration

355

356

```solidity

357

import "@openzeppelin/contracts/access/TimelockController.sol";

358

import "@openzeppelin/contracts/access/Ownable.sol";

359

360

contract GovernedContract is Ownable {

361

TimelockController public timelock;

362

363

constructor(address timelockAddress) {

364

timelock = TimelockController(payable(timelockAddress));

365

// Transfer ownership to timelock

366

transferOwnership(timelockAddress);

367

}

368

369

function sensitiveOperation(uint256 newValue) public onlyOwner {

370

// This can only be called by the timelock after delay

371

}

372

}

373

```