@lazy-sol/access-control 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,98 @@ A shortcut to a modular and easily pluggable dapp architecture.
4
4
  Enable the modular plug and play (PnP) architecture for your dapp by incorporating the role-based access control (RBAC)
5
5
  into the smart contracts.
6
6
 
7
+ ## Technical Overview
8
+
9
+ Role-based Access Control (RBAC), or simply Access Control, is the base parent contract to be inherited by other smart
10
+ contracts wishing to enable the RBAC feature. It provides an API to check if a specific operation is permitted globally
11
+ and/or if a particular user has a permission to execute it.
12
+
13
+ It deals with two main entities: features and roles. Features are designed to be used to enable/disable public functions
14
+ of the smart contract (used by a wide audience). User roles are designed to control the access to restricted functions
15
+ of the smart contract (used by a limited set of maintainers).
16
+
17
+ When designing the RBAC-enabled contract, the best practice is to make all public mutative functions controlled with
18
+ their corresponding feature flags, which can be enabled/disabled during smart contact deployment, setup process, and,
19
+ optionally, during contract operation.
20
+
21
+ Restricted access functions must be controlled by their corresponding user roles/permissions and usually can be executed
22
+ by the deployer during smart contract deployment and setup process.
23
+
24
+ After deployment is complete and smart contract setup is verified the deployer should enable the feature flags and
25
+ revoke own permissions to control these flags, as well as permissions to execute restricted access functions.
26
+
27
+ It is possible that smart contract functionalities are enabled in phases, but the intention is that eventually it is
28
+ also possible to set the smart contract to be uncontrolled by anyone and be fully decentralized.
29
+
30
+ It is also possible that the deployer shares its admin permissions with other addresses during the deployment and setup
31
+ process, but eventually all these permissions can be revoked from all the addresses involved.
32
+
33
+ Following diagram summarizes stated below:
34
+
35
+ ![Role-based Access Control (RBAC) Lifecycle](Role-based%20Access%20Control%20%28RBAC%29%20Lifecycle.png)
36
+ Diagram 1. RBAC-enabled smart contract deployment and setup phases. Contract evolves from the fully controlled in the
37
+ initial phases of the setup process to the fully decentralized and uncontrolled in the end.
38
+
39
+ It is important to note that it is not necessary, and not recommended to wait until the last “Setup Complete” phase is
40
+ executed to consider the protocol fully operational in the mainnet. In fact, the best practice is to do the launch after
41
+ the deployer permissions are revoked, but there are admin multisig accounts with the full permissions to control the
42
+ protocol. This kind of approach allows reacting to the security issues, which are more likely to happen in the beginning
43
+ of the protocol operation.
44
+
45
+ ## Special Permissions Mapping
46
+
47
+ Special permissions mapping, `userRoles`, stores special permissions of the smart contract administrators and helpers.
48
+ The mapping is a part of AccessControl and is inherited by the smart contracts using it.
49
+
50
+ The value stored in the mapping is a 256 bits unsigned integer, each bit of that integer represents a particular
51
+ permission. We call a set of permissions a role. Usually, roles are defined as 32 bits unsigned integer constants, but
52
+ extension to 255 bits is possible.
53
+
54
+ Permission with the bit 255 set is a special one. It corresponds to the access manager role `ROLE_ACCESS_MANAGER`
55
+ defined on the Access Control smart contract and allows accounts having that bit set to grant/revoke their permissions
56
+ to other addresses and to enable/disable corresponding features of the smart contract (to update self address “this”
57
+ role – see below).
58
+
59
+ Self address “this” mapping is a special one. It represents the deployed smart contract itself and defines features
60
+ enabled on it. Features control what public functions are enabled and how they behave. Usually, features are defined as
61
+ 32 bits unsigned integer constants, but extension to 255 bits is possible.
62
+
63
+ Access Control is a shared parent for other smart contracts which are free to use any strategy to introduce their
64
+ features and roles. Usually, smart contracts use different values for all the features and roles (see the table in the
65
+ next section).
66
+
67
+ Access manager may revoke its own permissions, including the bit 255. Eventually that allows an access manager to let
68
+ the smart contract “float freely” and be controlled only by the community (via DAO) or by no one at all.
69
+
70
+ ## Comparing with OpenZeppelin
71
+
72
+ Both our and OpenZeppelin Access Control implementations feature a similar API to check/know "who is allowed to do this
73
+ thing".
74
+
75
+ Zeppelin implementation is more flexible:
76
+ * it allows setting unlimited number of roles, while current is limited to 256 different roles
77
+ * it allows setting an admin for each role, while current allows having only one global admin
78
+
79
+ Our implementation is more lightweight:
80
+ * it uses only 1 bit per role, while Zeppelin uses 256 bits
81
+ * it allows setting up to 256 roles at once, in a single transaction, while Zeppelin allows setting only one role in a
82
+ single transaction
83
+
84
+ ## Upgradeability
85
+
86
+ [Upgradeable Access Control](https://github.com/lazy-sol/access-control-upgradeable) is a Role-based Access Control
87
+ extension supporting the OpenZeppelin UUPS Proxy upgrades. Smart contracts inheriting from the
88
+ `UpgradeableAccessControl` can be deployed behind the ERC1967 proxy and will get the upgradeability mechanism setup.
89
+
90
+ Upgradeable Access Control introduces another “special” permission bit 254 which is reserved for an upgrade manager role
91
+ `ROLE_UPGRADE_MANAGER` which is allowed to and is responsible for implementation upgrades of the ERC1967 Proxy.
92
+
93
+ Being controlled by the upgrade manager, the upgradeability is also a revocable feature of the smart contract: the
94
+ `upgradeTo` restricted function access can be revoked from all the admin accounts.
95
+
96
+ The best practice is to disable contract upgradeability when the protocol is mature enough and has already proven its
97
+ security and stability.
98
+
7
99
  ## Installation
8
100
  ```
9
101
  npm i -D @lazy-sol/access-control
package/hardhat.config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * default Hardhat configuration which uses account mnemonic to derive accounts
3
- * script expects following environment variables to be set:
3
+ * script supports the following environment variables set:
4
4
  * - P_KEY1 – mainnet private key, should start with 0x
5
5
  * or
6
6
  * - MNEMONIC1 – mainnet mnemonic, 12 words
@@ -53,6 +53,10 @@
53
53
  * or
54
54
  * - MNEMONIC84532 – Base Sepolia (testnet) Optimistic Rollup (L2) mnemonic, 12 words
55
55
  *
56
+ * - P_KEY – Custom network (defined by its JSON-RPC) private key, should start with 0x
57
+ * or
58
+ * - MNEMONIC – Custom network (defined by its JSON-RPC) mnemonic, 12 words
59
+ *
56
60
  * - ALCHEMY_KEY – Alchemy API key
57
61
  * or
58
62
  * - INFURA_KEY – Infura API key (Project ID)
@@ -85,6 +89,13 @@ require("hardhat-gas-reporter");
85
89
  // https://www.npmjs.com/package/hardhat-deploy
86
90
  require("hardhat-deploy");
87
91
 
92
+ // automatically generate TypeScript bindings for smart contracts while using Hardhat
93
+ // TypeScript bindings help IDEs to properly recognize compiled contracts' ABIs
94
+ // https://github.com/dethcrypto/TypeChain/tree/master/packages/hardhat
95
+ // npm install -D typechain @typechain/hardhat @typechain/truffle-v5
96
+ // run: npx hardhat typechain
97
+ // require("@typechain/hardhat");
98
+
88
99
  // verify environment setup, display warning if required, replace missing values with fakes
89
100
  const FAKE_MNEMONIC = "test test test test test test test test test test test junk";
90
101
  if(!process.env.MNEMONIC1 && !process.env.P_KEY1) {
@@ -185,19 +196,26 @@ else if(process.env.P_KEY84531 && !process.env.P_KEY84531.startsWith("0x")) {
185
196
  }
186
197
  if(!process.env.MNEMONIC84532 && !process.env.P_KEY84532) {
187
198
  console.warn("neither MNEMONIC84532 nor P_KEY84532 is not set. Base Sepolia (testnet) deployments won't be available");
188
- process.env.MNEMONIC84531 = FAKE_MNEMONIC;
199
+ process.env.MNEMONIC84532 = FAKE_MNEMONIC;
189
200
  }
190
201
  else if(process.env.P_KEY84532 && !process.env.P_KEY84532.startsWith("0x")) {
191
202
  console.warn("P_KEY84532 doesn't start with 0x. Appended 0x");
192
203
  process.env.P_KEY84532 = "0x" + process.env.P_KEY84532;
193
204
  }
205
+ if(!process.env.MNEMONIC && !process.env.P_KEY) {
206
+ process.env.MNEMONIC = FAKE_MNEMONIC;
207
+ }
208
+ else if(process.env.P_KEY && !process.env.P_KEY.startsWith("0x")) {
209
+ console.warn("P_KEY doesn't start with 0x. Appended 0x");
210
+ process.env.P_KEY = "0x" + process.env.P_KEY;
211
+ }
194
212
  if(!process.env.INFURA_KEY && !process.env.ALCHEMY_KEY) {
195
213
  console.warn("neither INFURA_KEY nor ALCHEMY_KEY is not set. Deployments may not be available");
196
214
  process.env.INFURA_KEY = "";
197
215
  process.env.ALCHEMY_KEY = "";
198
216
  }
199
217
  if(!process.env.ETHERSCAN_KEY) {
200
- console.warn("ETHERSCAN_KEY is not set. Deployed smart contract code verification won't be available");
218
+ console.warn("ETHERSCAN_KEY is not set. Deployed smart contract code verification won't be available on etherscan");
201
219
  process.env.ETHERSCAN_KEY = "";
202
220
  }
203
221
  if(!process.env.POLYSCAN_KEY) {
@@ -210,6 +228,7 @@ if(!process.env.BSCSCAN_KEY) {
210
228
  }
211
229
  if(!process.env.BASESCAN_KEY) {
212
230
  console.warn("BASESCAN_KEY is not set. Deployed smart contract code verification won't be available on BaseScan");
231
+ process.env.BASESCAN_KEY = "";
213
232
  }
214
233
 
215
234
  /**
@@ -303,6 +322,10 @@ module.exports = {
303
322
  url: get_endpoint_url("base_sepolia"),
304
323
  accounts: get_accounts(process.env.P_KEY84532, process.env.MNEMONIC84532),
305
324
  },
325
+ custom: {
326
+ url: get_endpoint_url(),
327
+ accounts: get_accounts(process.env.P_KEY, process.env.MNEMONIC),
328
+ },
306
329
  },
307
330
 
308
331
  // Configure Solidity compiler
@@ -348,6 +371,12 @@ module.exports = {
348
371
  ]
349
372
  },
350
373
 
374
+ // configure typechain to generate Truffle v5 bindings
375
+ typechain: {
376
+ outDir: "typechain",
377
+ target: "truffle-v5",
378
+ },
379
+
351
380
  // Set default mocha options here, use special reporters etc.
352
381
  mocha: {
353
382
  // timeout: 100000,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazy-sol/access-control",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Enable the modular plug and play (PnP) architecture for your dapp by incorporating the role-based access control (RBAC) into the smart contracts",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,13 +22,13 @@
22
22
  "author": "Basil Gorin",
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
- "@lazy-sol/a-missing-gem": "^1.0.4",
25
+ "@lazy-sol/a-missing-gem": "^1.0.9",
26
26
  "@nomiclabs/hardhat-truffle5": "^2.0.7",
27
- "hardhat": "^2.22.4",
27
+ "hardhat": "^2.22.6",
28
28
  "hardhat-deploy": "^0.11.45"
29
29
  },
30
30
  "devDependencies": {
31
- "@lazy-sol/zeppelin-test-helpers": "^1.0.0",
31
+ "@lazy-sol/zeppelin-test-helpers": "^1.0.1",
32
32
  "hardhat-gas-reporter": "^1.0.10",
33
33
  "solidity-coverage": "^0.8.12"
34
34
  },