@lazy-sol/access-control 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
- // deploy: npx hardhat deploy --network goerli --tags AdapterFactory
2
- // verify: npx hardhat etherscan-verify --network goerli --api-key $ETHERSCAN_KEY
1
+ // deploy: npx hardhat deploy --network sepolia --tags AdapterFactory
2
+ // verify: npx hardhat etherscan-verify --network sepolia --api-key $ETHERSCAN_KEY
3
3
 
4
4
  // script is built for hardhat-deploy plugin:
5
5
  // A Hardhat Plugin For Replicable Deployments And Easy Testing
@@ -9,7 +9,7 @@
9
9
  const {
10
10
  print_amt,
11
11
  print_contract_details,
12
- } = require("@lazy-sol/a-missing-jem/deployment_utils");
12
+ } = require("@lazy-sol/a-missing-gem/deployment_utils");
13
13
 
14
14
  // to be picked up and executed by hardhat-deploy plugin
15
15
  module.exports = async function({deployments, getChainId, getNamedAccounts, getUnnamedAccounts}) {
@@ -0,0 +1 @@
1
+ 11155111
@@ -0,0 +1,104 @@
1
+ {
2
+ "address": "0x8492C8E14f168eE6b4f97e7e83d9351558c35F92",
3
+ "abi": [
4
+ {
5
+ "anonymous": false,
6
+ "inputs": [
7
+ {
8
+ "indexed": true,
9
+ "internalType": "address",
10
+ "name": "adapterAddress",
11
+ "type": "address"
12
+ },
13
+ {
14
+ "indexed": true,
15
+ "internalType": "address",
16
+ "name": "ownableTargetAddress",
17
+ "type": "address"
18
+ }
19
+ ],
20
+ "name": "NewOwnableToAccessControlAdapterDeployed",
21
+ "type": "event"
22
+ },
23
+ {
24
+ "inputs": [
25
+ {
26
+ "internalType": "address",
27
+ "name": "targetAddress",
28
+ "type": "address"
29
+ }
30
+ ],
31
+ "name": "deployNewOwnableToAccessControlAdapter",
32
+ "outputs": [
33
+ {
34
+ "internalType": "address",
35
+ "name": "",
36
+ "type": "address"
37
+ }
38
+ ],
39
+ "stateMutability": "nonpayable",
40
+ "type": "function"
41
+ }
42
+ ],
43
+ "transactionHash": "0xa6a80322de08699f1cd9855b795ee9ac8157fcdeb77e4975e8e3bc14b190c741",
44
+ "receipt": {
45
+ "to": null,
46
+ "from": "0x5F185Da55f7BBD9217E3b3CeE06b180721FA6d34",
47
+ "contractAddress": "0x8492C8E14f168eE6b4f97e7e83d9351558c35F92",
48
+ "transactionIndex": 33,
49
+ "gasUsed": "799387",
50
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
51
+ "blockHash": "0xa76b1d24af16e1bddd22624c739dd62ae0d133d0bb208dcd5d7b3e2cf07e07ee",
52
+ "transactionHash": "0xa6a80322de08699f1cd9855b795ee9ac8157fcdeb77e4975e8e3bc14b190c741",
53
+ "logs": [],
54
+ "blockNumber": 5505074,
55
+ "cumulativeGasUsed": "5177230",
56
+ "status": 1,
57
+ "byzantium": true
58
+ },
59
+ "args": [],
60
+ "numDeployments": 1,
61
+ "solcInputHash": "f3b0c8e313d75e7b1407fbf8bd948f3c",
62
+ "metadata": "{\"compiler\":{\"version\":\"0.8.21+commit.d9974bed\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"adapterAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"ownableTargetAddress\",\"type\":\"address\"}],\"name\":\"NewOwnableToAccessControlAdapterDeployed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"targetAddress\",\"type\":\"address\"}],\"name\":\"deployNewOwnableToAccessControlAdapter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Basil Gorin\",\"events\":{\"NewOwnableToAccessControlAdapterDeployed(address,address)\":{\"details\":\"Fired in deployNewOwnableToAccessControlAdapter\",\"params\":{\"adapterAddress\":\"newly deployed OwnableToAccessControlAdapter address\",\"ownableTargetAddress\":\"OZ Ownable target contract address\"}}},\"kind\":\"dev\",\"methods\":{\"deployNewOwnableToAccessControlAdapter(address)\":{\"params\":{\"targetAddress\":\"OZ Ownable target address to bind OwnableToAccessControlAdapter to\"},\"returns\":{\"_0\":\"address of the newly deployed OwnableToAccessControlAdapter contract\"}}},\"title\":\"Adapter Factory\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deployNewOwnableToAccessControlAdapter(address)\":{\"notice\":\"Deploys new OwnableToAccessControlAdapter bound to the OZ Ownable contract specified. Can be executed only by the OZ Ownable target owner. This owner is expected to transfer the ownership to the newly deployed OwnableToAccessControlAdapter contract address.\"}},\"notice\":\"Helper contract simplifying the deployment of the OwnableToAccessControlAdapter\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/AdapterFactory.sol\":\"AdapterFactory\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.4.22; // require with message (0.4.22), pure/view modifiers (0.4.16), hardhat (0.4.11)\\n\\n/**\\n * @title Role-based Access Control (RBAC)\\n *\\n * @notice Access control smart contract provides an API to check\\n * if a specific operation is permitted globally and/or\\n * if a particular user has a permission to execute it.\\n *\\n * @notice This contract is inherited by other contracts requiring the role-based access control (RBAC)\\n * protection for the restricted access functions\\n *\\n * @notice It deals with two main entities: features and roles.\\n *\\n * @notice Features are designed to be used to enable/disable public functions\\n * of the smart contract (used by a wide audience).\\n * @notice User roles are designed to control the access to restricted functions\\n * of the smart contract (used by a limited set of maintainers).\\n *\\n * @notice Terms \\\"role\\\", \\\"permissions\\\" and \\\"set of permissions\\\" have equal meaning\\n * in the documentation text and may be used interchangeably.\\n * @notice Terms \\\"permission\\\", \\\"single permission\\\" implies only one permission bit set.\\n *\\n * @notice Access manager is a special role which allows to grant/revoke other roles.\\n * Access managers can only grant/revoke permissions which they have themselves.\\n * As an example, access manager with no other roles set can only grant/revoke its own\\n * access manager permission and nothing else.\\n *\\n * @notice Access manager permission should be treated carefully, as a super admin permission:\\n * Access manager with even no other permission can interfere with another account by\\n * granting own access manager permission to it and effectively creating more powerful\\n * permission set than its own.\\n *\\n * @dev Both current and OpenZeppelin AccessControl implementations feature a similar API\\n * to check/know \\\"who is allowed to do this thing\\\".\\n * @dev Zeppelin implementation is more flexible:\\n * - it allows setting unlimited number of roles, while current is limited to 256 different roles\\n * - it allows setting an admin for each role, while current allows having only one global admin\\n * @dev Current implementation is more lightweight:\\n * - it uses only 1 bit per role, while Zeppelin uses 256 bits\\n * - it allows setting up to 256 roles at once, in a single transaction, while Zeppelin allows\\n * setting only one role in a single transaction\\n *\\n * @dev This smart contract is designed to be inherited by other\\n * smart contracts which require access control management capabilities.\\n *\\n * @dev Access manager permission has a bit 255 set.\\n * This bit must not be used by inheriting contracts for any other permissions/features.\\n *\\n * @author Basil Gorin\\n */\\nabstract contract AccessControl {\\n\\t/**\\n\\t * @dev Privileged addresses with defined roles/permissions\\n\\t * @dev In the context of ERC20/ERC721 tokens these can be permissions to\\n\\t * allow minting or burning tokens, transferring on behalf and so on\\n\\t *\\n\\t * @dev Maps user address to the permissions bitmask (role), where each bit\\n\\t * represents a permission\\n\\t * @dev Bitmask 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\\n\\t * represents all possible permissions\\n\\t * @dev 'This' address mapping represents global features of the smart contract\\n\\t *\\n\\t * @dev We keep the mapping private to prevent direct writes to it from the inheriting\\n\\t * contracts, `getRole()` and `updateRole()` functions should be used instead\\n\\t */\\n\\tmapping(address => uint256) private userRoles;\\n\\n\\t/**\\n\\t * @notice Access manager is responsible for assigning the roles to users,\\n\\t * enabling/disabling global features of the smart contract\\n\\t * @notice Access manager can add, remove and update user roles,\\n\\t * remove and update global features\\n\\t *\\n\\t * @dev Role ROLE_ACCESS_MANAGER allows modifying user roles and global features\\n\\t * @dev Role ROLE_ACCESS_MANAGER has single bit at position 255 enabled\\n\\t */\\n\\tuint256 public constant ROLE_ACCESS_MANAGER = 0x8000000000000000000000000000000000000000000000000000000000000000;\\n\\n\\t/**\\n\\t * @dev Bitmask representing all the possible permissions (super admin role)\\n\\t * @dev Has all the bits are enabled (2^256 - 1 value)\\n\\t */\\n\\tuint256 internal constant FULL_PRIVILEGES_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;\\n\\n\\t/**\\n\\t * @dev Fired in updateRole() and updateFeatures()\\n\\t *\\n\\t * @param operator address which was granted/revoked permissions\\n\\t * @param requested permissions requested\\n\\t * @param assigned permissions effectively set\\n\\t */\\n\\tevent RoleUpdated(address indexed operator, uint256 requested, uint256 assigned);\\n\\n\\t/**\\n\\t * @notice Function modifier making a function defined as public behave as restricted\\n\\t * (so that only a pre-configured set of accounts can execute it)\\n\\t *\\n\\t * @param role the role transaction executor is required to have;\\n\\t * the function throws an \\\"access denied\\\" exception if this condition is not met\\n\\t */\\n\\tmodifier restrictedTo(uint256 role) {\\n\\t\\t// verify the access permission\\n\\t\\trequire(isSenderInRole(role), \\\"access denied\\\");\\n\\n\\t\\t// execute the rest of the function\\n\\t\\t_;\\n\\t}\\n\\n\\t/**\\n\\t * @notice Creates an access control instance, setting the contract owner to have full privileges\\n\\t *\\n\\t * @param _owner smart contract owner having full privileges, can be zero\\n\\t * @param _features initial features mask of the contract, can be zero\\n\\t */\\n\\tconstructor(address _owner, uint256 _features) internal { // visibility modifier is required to be compilable with 0.6.x\\n\\t\\t// grant owner full privileges\\n\\t\\t__setRole(_owner, FULL_PRIVILEGES_MASK, FULL_PRIVILEGES_MASK);\\n\\t\\t// update initial features bitmask\\n\\t\\t__setRole(address(this), _features, _features);\\n\\t}\\n\\n\\t/**\\n\\t * @notice Retrieves globally set of features enabled\\n\\t *\\n\\t * @dev Effectively reads userRoles role for the contract itself\\n\\t *\\n\\t * @return 256-bit bitmask of the features enabled\\n\\t */\\n\\tfunction features() public view returns (uint256) {\\n\\t\\t// features are stored in 'this' address mapping of `userRoles`\\n\\t\\treturn getRole(address(this));\\n\\t}\\n\\n\\t/**\\n\\t * @notice Updates set of the globally enabled features (`features`),\\n\\t * taking into account sender's permissions\\n\\t *\\n\\t * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission\\n\\t * @dev Function is left for backward compatibility with older versions\\n\\t *\\n\\t * @param _mask bitmask representing a set of features to enable/disable\\n\\t */\\n\\tfunction updateFeatures(uint256 _mask) public {\\n\\t\\t// delegate call to `updateRole`\\n\\t\\tupdateRole(address(this), _mask);\\n\\t}\\n\\n\\t/**\\n\\t * @notice Reads the permissions (role) for a given user from the `userRoles` mapping\\n\\t * (privileged addresses with defined roles/permissions)\\n\\t * @notice In the context of ERC20/ERC721 tokens these can be permissions to\\n\\t * allow minting or burning tokens, transferring on behalf and so on\\n\\t *\\n\\t * @dev Having a simple getter instead of making the mapping public\\n\\t * allows enforcing the encapsulation of the mapping and protects from\\n\\t * writing to it directly in the inheriting smart contracts\\n\\t *\\n\\t * @param operator address of a user to read permissions for,\\n\\t * or self address to read global features of the smart contract\\n\\t */\\n\\tfunction getRole(address operator) public view returns(uint256) {\\n\\t\\t// read the value from `userRoles` and return\\n\\t\\treturn userRoles[operator];\\n\\t}\\n\\n\\t/**\\n\\t * @notice Updates set of permissions (role) for a given user,\\n\\t * taking into account sender's permissions.\\n\\t *\\n\\t * @dev Setting role to zero is equivalent to removing an all permissions\\n\\t * @dev Setting role to `FULL_PRIVILEGES_MASK` is equivalent to\\n\\t * copying senders' permissions (role) to the user\\n\\t * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission\\n\\t *\\n\\t * @param operator address of a user to alter permissions for,\\n\\t * or self address to alter global features of the smart contract\\n\\t * @param role bitmask representing a set of permissions to\\n\\t * enable/disable for a user specified\\n\\t */\\n\\tfunction updateRole(address operator, uint256 role) public {\\n\\t\\t// caller must have a permission to update user roles\\n\\t\\trequire(isSenderInRole(ROLE_ACCESS_MANAGER), \\\"access denied\\\");\\n\\n\\t\\t// evaluate the role and reassign it\\n\\t\\t__setRole(operator, role, _evaluateBy(msg.sender, getRole(operator), role));\\n\\t}\\n\\n\\t/**\\n\\t * @notice Determines the permission bitmask an operator can set on the\\n\\t * target permission set\\n\\t * @notice Used to calculate the permission bitmask to be set when requested\\n\\t * in `updateRole` and `updateFeatures` functions\\n\\t *\\n\\t * @dev Calculated based on:\\n\\t * 1) operator's own permission set read from userRoles[operator]\\n\\t * 2) target permission set - what is already set on the target\\n\\t * 3) desired permission set - what do we want set target to\\n\\t *\\n\\t * @dev Corner cases:\\n\\t * 1) Operator is super admin and its permission set is `FULL_PRIVILEGES_MASK`:\\n\\t * `desired` bitset is returned regardless of the `target` permission set value\\n\\t * (what operator sets is what they get)\\n\\t * 2) Operator with no permissions (zero bitset):\\n\\t * `target` bitset is returned regardless of the `desired` value\\n\\t * (operator has no authority and cannot modify anything)\\n\\t *\\n\\t * @dev Example:\\n\\t * Consider an operator with the permissions bitmask 00001111\\n\\t * is about to modify the target permission set 01010101\\n\\t * Operator wants to set that permission set to 00110011\\n\\t * Based on their role, an operator has the permissions\\n\\t * to update only lowest 4 bits on the target, meaning that\\n\\t * high 4 bits of the target set in this example is left\\n\\t * unchanged and low 4 bits get changed as desired: 01010011\\n\\t *\\n\\t * @param operator address of the contract operator which is about to set the permissions\\n\\t * @param target input set of permissions to operator is going to modify\\n\\t * @param desired desired set of permissions operator would like to set\\n\\t * @return resulting set of permissions given operator will set\\n\\t */\\n\\tfunction _evaluateBy(address operator, uint256 target, uint256 desired) internal view returns (uint256) {\\n\\t\\t// read operator's permissions\\n\\t\\tuint256 p = getRole(operator);\\n\\n\\t\\t// taking into account operator's permissions,\\n\\t\\t// 1) enable the permissions desired on the `target`\\n\\t\\ttarget |= p & desired;\\n\\t\\t// 2) disable the permissions desired on the `target`\\n\\t\\ttarget &= FULL_PRIVILEGES_MASK ^ (p & (FULL_PRIVILEGES_MASK ^ desired));\\n\\n\\t\\t// return calculated result\\n\\t\\treturn target;\\n\\t}\\n\\n\\t/**\\n\\t * @notice Checks if requested set of features is enabled globally on the contract\\n\\t *\\n\\t * @param required set of features to check against\\n\\t * @return true if all the features requested are enabled, false otherwise\\n\\t */\\n\\tfunction isFeatureEnabled(uint256 required) public view returns (bool) {\\n\\t\\t// delegate call to `__hasRole`, passing `features` property\\n\\t\\treturn __hasRole(features(), required);\\n\\t}\\n\\n\\t/**\\n\\t * @notice Checks if transaction sender `msg.sender` has all the permissions required\\n\\t *\\n\\t * @param required set of permissions (role) to check against\\n\\t * @return true if all the permissions requested are enabled, false otherwise\\n\\t */\\n\\tfunction isSenderInRole(uint256 required) public view returns (bool) {\\n\\t\\t// delegate call to `isOperatorInRole`, passing transaction sender\\n\\t\\treturn isOperatorInRole(msg.sender, required);\\n\\t}\\n\\n\\t/**\\n\\t * @notice Checks if operator has all the permissions (role) required\\n\\t *\\n\\t * @param operator address of the user to check role for\\n\\t * @param required set of permissions (role) to check\\n\\t * @return true if all the permissions requested are enabled, false otherwise\\n\\t */\\n\\tfunction isOperatorInRole(address operator, uint256 required) public view returns (bool) {\\n\\t\\t// delegate call to `__hasRole`, passing operator's permissions (role)\\n\\t\\treturn __hasRole(getRole(operator), required);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Sets the `assignedRole` role to the operator, logs both `requestedRole` and `actualRole`\\n\\t *\\n\\t * @dev Unsafe:\\n\\t * provides direct write access to `userRoles` mapping without any security checks,\\n\\t * doesn't verify the executor (msg.sender) permissions,\\n\\t * must be kept private at all times\\n\\t *\\n\\t * @param operator address of a user to alter permissions for,\\n\\t * or self address to alter global features of the smart contract\\n\\t * @param requestedRole bitmask representing a set of permissions requested\\n\\t * to be enabled/disabled for a user specified, used only to be logged into event\\n\\t * @param assignedRole bitmask representing a set of permissions to\\n\\t * enable/disable for a user specified, used to update the mapping and to be logged into event\\n\\t */\\n\\tfunction __setRole(address operator, uint256 requestedRole, uint256 assignedRole) private {\\n\\t\\t// assign the role to the operator\\n\\t\\tuserRoles[operator] = assignedRole;\\n\\n\\t\\t// fire an event\\n\\t\\temit RoleUpdated(operator, requestedRole, assignedRole);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Checks if role `actual` contains all the permissions required `required`\\n\\t *\\n\\t * @param actual existent role\\n\\t * @param required required role\\n\\t * @return true if actual has required role (all permissions), false otherwise\\n\\t */\\n\\tfunction __hasRole(uint256 actual, uint256 required) private pure returns (bool) {\\n\\t\\t// check the bitmask for the role required and return the result\\n\\t\\treturn actual & required == required;\\n\\t}\\n}\\n\",\"keccak256\":\"0x73c5e8ea10b78b40374c652e55be9684b4c0a6f22e7f7194a279b335462d908a\",\"license\":\"MIT\"},\"contracts/AdapterFactory.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.6.2;\\n\\nimport \\\"./OwnableToAccessControlAdapter.sol\\\";\\n\\n/**\\n * @notice Ownable is a contract which is aware of its owner, that is has owner() function\\n */\\ninterface Ownable {\\n\\t/**\\n\\t * @notice Smart contract owner\\n\\t *\\n\\t * @return the address of the smart contract owner\\n\\t */\\n\\tfunction owner() external returns(address);\\n}\\n\\n/**\\n * @title Adapter Factory\\n *\\n * @notice Helper contract simplifying the deployment of the OwnableToAccessControlAdapter\\n *\\n * @author Basil Gorin\\n */\\ncontract AdapterFactory {\\n\\t/**\\n\\t * @dev Fired in deployNewOwnableToAccessControlAdapter\\n\\t *\\n\\t * @param adapterAddress newly deployed OwnableToAccessControlAdapter address\\n\\t * @param ownableTargetAddress OZ Ownable target contract address\\n\\t */\\n\\tevent NewOwnableToAccessControlAdapterDeployed(address indexed adapterAddress, address indexed ownableTargetAddress);\\n\\n\\t/**\\n\\t * @notice Deploys new OwnableToAccessControlAdapter bound to the OZ Ownable contract specified.\\n\\t * Can be executed only by the OZ Ownable target owner. This owner is expected to transfer\\n\\t * the ownership to the newly deployed OwnableToAccessControlAdapter contract address.\\n\\t *\\n\\t * @param targetAddress OZ Ownable target address to bind OwnableToAccessControlAdapter to\\n\\t * @return address of the newly deployed OwnableToAccessControlAdapter contract\\n\\t */\\n\\tfunction deployNewOwnableToAccessControlAdapter(address targetAddress) public returns(address) {\\n\\t\\t// verify sender is a target owner\\n\\t\\trequire(Ownable(targetAddress).owner() == msg.sender, \\\"not an owner\\\");\\n\\n\\t\\t// deploy the OwnableToAccessControlAdapter\\n\\t\\t// and set its ownership immediately to the tx executor (msg.sender)\\n\\t\\taddress adapterAddress = address(new OwnableToAccessControlAdapter(targetAddress, msg.sender));\\n\\n\\t\\t// emit an event\\n\\t\\temit NewOwnableToAccessControlAdapterDeployed(adapterAddress, targetAddress);\\n\\n\\t\\t// return address of the newly deployed OwnableToAccessControlAdapter contract\\n\\t\\treturn adapterAddress;\\n\\t}\\n}\\n\",\"keccak256\":\"0xbbf12d09d01ef373184fba4077b9f931c1ddb65ccfbf6e1f1d82b62c5e9ef4dc\",\"license\":\"MIT\"},\"contracts/OwnableToAccessControlAdapter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.6.2; // breaking changes in .call() (0.5.0), allow .call{}() (0.6.2)\\n\\nimport \\\"./AccessControl.sol\\\";\\n\\n/**\\n * @title OZ Ownable to AccessControl Adapter (short: AccessControl Adapter)\\n *\\n * @notice Helper contract allowing to change the access model of the already deployed\\n * OpenZeppelin Ownable contract to the AccessControl model\\n *\\n * @dev Installation Flow\\n * Prerequisite: deployed OZ Ownable contract (target contract) address (target_address)\\n *\\n * 1. Deploy the AccessControl Adapter bound to the already deployed OZ Ownable contract\\n * (specify the target OZ Ownable contract address in the constructor upon the deployment)\\n *\\n * const adapter = await (artifacts.require(\\\"OwnableToAccessControlAdapter\\\")).new(target_address);\\n *\\n * 2. Define what Ownable-restricted public functions on the target contract you'd like to be able\\n * to provide access to through the adapter contract\\n *\\n * 3. Map every such function with the role required to execute it using `updateAccessRole()` function\\n * For example, to be able to provide an access to the transferOwnership(address) function, you could do\\n *\\n * const ROLE_TRANSFER_OWNERSHIP_MANAGER = 0x00010000;\\n * await adapter.updateAccessRole(\\\"transferOwnership(address)\\\", ROLE_TRANSFER_OWNERSHIP_MANAGER);\\n *\\n * 4. Provide the roles to the corresponding operators as you would usually do with AccessControl\\n * For example, if you wish an address 0x00000000000000000000000000000000000Ff1CE to grant an access to the\\n * transferOwnership(address) function on the target, you could do\\n *\\n * const operator = \\\"0x00000000000000000000000000000000000Ff1CE\\\";\\n * await adapter.updateRole(operator, ROLE_TRANSFER_OWNERSHIP_MANAGER);\\n *\\n * 5. Transfer the ownership of the target contract to the deployed AccessControl Adapter contract\\n * Note that you can also do steps 2-4 after the step 5\\n *\\n * @dev Usage Flow\\n * Prerequisite: installed AccessControl Adapter with the access to at least one restricted target contract\\n * function configured\\n *\\n * To execute the restricted access function on the target contract via the AccessControl Adapter\\n * 1. Use target contract ABI to construct a low-level function call calldata\\n * For example, to construct the transferOwnership() function calldata to transfer the ownership to the\\n * 0x00000000000000000000000000000000DEAdc0De address, you could do\\n *\\n * const to = \\\"0x00000000000000000000000000000000DEAdc0De\\\";\\n * const calldata = target.contract.methods.transferOwnership(to).encodeABI();\\n *\\n * 2. Execute a low-level function call on the AccessControl Adapter contract using the constructed calldata\\n * For example, to execute the transferOwnership() function (prepared in step 1), you could do\\n *\\n * await web3.eth.sendTransaction({\\n * from: operator,\\n * to: adapter.address,\\n * data: calldata,\\n * }\\n *\\n * 3. It is also ok to add an ether to the transaction by adding a value field to the `sendTransaction` call,\\n * as well as sending plain ether transfer transaction, as long as target contract has payable functions,\\n * and/or has a default payable receiver\\n *\\n * @author Basil Gorin\\n */\\ncontract OwnableToAccessControlAdapter is AccessControl {\\n\\t/**\\n\\t * @dev Target OZ Ownable contract AccessControl Adapter executes the transactions on\\n\\t *\\n\\t * @dev Target contract must transfer its ownership to the AccessControl Adapter\\n\\t */\\n\\taddress public target;\\n\\n\\t/**\\n\\t * @dev Access roles mapping stores the roles required to access the functions on the\\n\\t * target contract, guarding it from the unauthorized access\\n\\t *\\n\\t * @dev Maps function selector (bytes4) on the target contract to the access role (permission)\\n\\t * required to execute the function\\n\\t */\\n\\tmapping(bytes4 => uint256) public accessRoles;\\n\\n\\t/**\\n\\t * @notice Access Roles manager is responsible for assigning the access roles to functions\\n\\t *\\n\\t * @dev Role ROLE_ACCESS_MANAGER allows modifying `accessRoles` mapping\\n\\t */\\n\\tuint256 public constant ROLE_ACCESS_ROLES_MANAGER = 0x2000000000000000000000000000000000000000000000000000000000000000;\\n\\n\\t/**\\n\\t * @dev Fired in `updateAccessRole` when the `accessRoles` mapping is updated\\n\\t *\\n\\t * @param selector selector of the function which corresponding access role was updated\\n\\t * @param role effective required role to execute the function defined by the selector\\n\\t */\\n\\tevent AccessRoleUpdated(bytes4 selector, uint256 role);\\n\\n\\t/**\\n\\t * @dev Logs function execution result on the target if the execution completed successfully\\n\\t *\\n\\t * @param selector selector of the function which was executed on the target contract\\n\\t * @param data full calldata payload passed to the target contract (includes the 4-bytes selector)\\n\\t * @param result execution response from the target contract\\n\\t */\\n\\tevent ExecutionComplete(bytes4 selector, bytes data, bytes result);\\n\\n\\t/**\\n\\t * @dev Deploys an AccessControl Adapter binding it to the target OZ Ownable contract,\\n\\t * and setting the ownership of the adapter itself to the deployer\\n\\t *\\n\\t * @param _target target OZ Ownable contract address\\n\\t * @param _owner smart contract owner having full privileges\\n\\t */\\n\\tconstructor(address _target, address _owner) public AccessControl(_owner, 0) {\\n\\t\\t// verify the inputs\\n\\t\\trequire(_target != address(0), \\\"zero address\\\");\\n\\n\\t\\t// initialize internal contract state\\n\\t\\ttarget = _target;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Updates the access role required to execute the function defined by its signature\\n\\t * on the target contract\\n\\t *\\n\\t * @dev More on function signatures and selectors: https://docs.soliditylang.org/en/develop/abi-spec.html\\n\\t *\\n\\t * @param signature function signature on the target contract, for example\\n\\t * \\\"transferOwnership(address)\\\"\\n\\t * @param role role required to execute this function, or zero to disable\\n\\t * access to the specified function for everyone\\n\\t */\\n\\tfunction updateAccessRole(string memory signature, uint256 role) public {\\n\\t\\t// delegate to `updateAccessRole(bytes4, uint256)`\\n\\t\\tupdateAccessRole(bytes4(keccak256(bytes(signature))), role);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Updates the access role required to execute the function defined by its selector\\n\\t * on the target contract\\n\\t *\\n\\t * @dev More on function signatures and selectors: https://docs.soliditylang.org/en/develop/abi-spec.html\\n\\t *\\n\\t * @param selector function selector on the target contract, for example\\n\\t * 0xf2fde38b selector corresponds to the \\\"transferOwnership(address)\\\" function\\n\\t * @param role role required to execute this function, or zero to disable\\n\\t * access to the specified function for everyone\\n\\t */\\n\\tfunction updateAccessRole(bytes4 selector, uint256 role) public {\\n\\t\\t// verify the access permission\\n\\t\\trequire(isSenderInRole(ROLE_ACCESS_ROLES_MANAGER), \\\"access denied\\\");\\n\\n\\t\\t// update the function access role\\n\\t\\taccessRoles[selector] = role;\\n\\n\\t\\t// emit an event\\n\\t\\temit AccessRoleUpdated(selector, role);\\n\\t}\\n\\n\\t/**\\n\\t * @dev Low-level execute of the data calldata on the target contract\\n\\t *\\n\\t * @dev This function extracts the target function selector from the calldata specified\\n\\t * and verifies transaction executor permission to access the function on the target\\n\\t * using the `accessRoles` mapping\\n\\t *\\n\\t * @dev Throws if there is no `accessRoles` mapping configured for the function\\n\\t * @dev Throws if transaction executor role doesn't contain the required role from `accessRoles` mapping\\n\\t * @dev Throws if execution on the target returns an error\\n\\t *\\n\\t * @param data low-level calldata to be passed as is to the target contract for the execution\\n\\t * @return the response from the target contract after the successful execution\\n\\t */\\n\\tfunction execute(bytes memory data) public payable returns(bytes memory) {\\n\\t\\t// extract the selector (first 4 bytes as bytes4) using assembly\\n\\t\\tbytes4 selector;\\n\\t\\tassembly {\\n\\t\\t\\t// load the first word after the length field\\n\\t\\t\\tselector := mload(add(data, 32))\\n\\t\\t}\\n\\n\\t\\t// zero data length means we're trying to execute the receive() function on\\n\\t\\t// the target and supply some ether to the target; in this case we don't need a security check\\n\\t\\t// if the data is present, we're executing some real function and must do a security check\\n\\t\\tif(data.length != 0) {\\n\\t\\t\\t// determine the role required to access the function\\n\\t\\t\\tuint256 roleRequired = accessRoles[selector];\\n\\n\\t\\t\\t// verify function access role was already set\\n\\t\\t\\trequire(roleRequired != 0, \\\"access role not set\\\");\\n\\n\\t\\t\\t// verify the access permission\\n\\t\\t\\trequire(isSenderInRole(roleRequired), \\\"access denied\\\");\\n\\t\\t}\\n\\n\\t\\t// execute the call on the target\\n\\t\\t(bool success, bytes memory result) = address(target).call{value: msg.value}(data);\\n\\n\\t\\t// verify the execution completed successfully\\n\\t\\trequire(success, \\\"execution failed\\\");\\n\\n\\t\\t// emit an event\\n\\t\\temit ExecutionComplete(selector, data, result);\\n\\n\\t\\t// return the result\\n\\t\\treturn result;\\n\\t}\\n\\n\\t/**\\n\\t * @dev Proxies the ether sent to the AccessControl Adapter to the target contract\\n\\t *\\n\\t * @dev Throws if target contract doesn't have the default payable receiver, i.e. doesn't accept ether\\n\\t */\\n\\treceive() external payable {\\n\\t\\t// delegate to `execute(bytes)`\\n\\t\\texecute(bytes(\\\"\\\"));\\n\\t}\\n\\n\\t/**\\n\\t * @dev Calls the target contract with the calldata specified in the transaction\\n\\t *\\n\\t * @dev See `execute()` function for details\\n\\t * @dev Use `execute()` function directly if the target contract function signature collides\\n\\t * with any of the AccessControl Adapter functions signature\\n\\t */\\n\\tfallback() external payable {\\n\\t\\t// msg.data contains full calldata: function selector + encoded function arguments (if any)\\n\\t\\t// delegate to `execute(bytes)`\\n\\t\\texecute(msg.data);\\n\\t}\\n}\\n\",\"keccak256\":\"0xb268fa69a5c803620da80c065a26b7e6c54d10cdb520e0141b01725afd90e70a\",\"license\":\"MIT\"}},\"version\":1}",
63
+ "bytecode": "0x608060405234801561001057600080fd5b50610d80806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80635020380814610030575b600080fd5b61004361003e3660046101c9565b61005f565b6040516001600160a01b03909116815260200160405180910390f35b6000336001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156100ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100cf91906101ed565b6001600160a01b0316146101185760405162461bcd60e51b815260206004820152600c60248201526b3737ba1030b71037bbb732b960a11b604482015260640160405180910390fd5b60008233604051610128906101a4565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801561015b573d6000803e3d6000fd5b509050826001600160a01b0316816001600160a01b03167f480c2ac1e89311d31b5f348c0934382be45d3bb75dfe35f2f209652fed1505b360405160405180910390a392915050565b610b408061020b83390190565b6001600160a01b03811681146101c657600080fd5b50565b6000602082840312156101db57600080fd5b81356101e6816101b1565b9392505050565b6000602082840312156101ff57600080fd5b81516101e6816101b156fe608060405234801561001057600080fd5b50604051610b40380380610b4083398101604081905261002f9161012f565b80600061003f82600019806100bb565b61004a3082806100bb565b50506001600160a01b0382166100955760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b604482015260640160405180910390fd5b50600180546001600160a01b0319166001600160a01b0392909216919091179055610162565b6001600160a01b0383166000818152602081815260409182902084905581518581529081018490527fe9be537308880e0f56b7d7cfd7abf85f14c4934486d138f848b92a0cbaf659b4910160405180910390a2505050565b80516001600160a01b038116811461012a57600080fd5b919050565b6000806040838503121561014257600080fd5b61014b83610113565b915061015960208401610113565b90509250929050565b6109cf806101716000396000f3fe6080604052600436106100e15760003560e01c8063725f36261161007f578063c688d69311610059578063c688d693146102bc578063d4b83992146102dc578063d5bb7f6714610314578063fcc2c0781461033457610100565b8063725f362614610254578063ae5b102e14610284578063ae682e2e146102a457610100565b806334e48c9e116100bb57806334e48c9e146101c657806344276733146101de578063491d2611146102145780635defb40d1461023457610100565b806309c5eabe146101405780630e82fe25146101695780632b521416146101a457610100565b36610100576100fe60405180602001604052806000815250610354565b005b6100fe6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061035492505050565b61015361014e366004610742565b610354565b60405161016091906107e3565b60405180910390f35b34801561017557600080fd5b50610196610184366004610813565b60026020526000908152604090205481565b604051908152602001610160565b3480156101b057600080fd5b5030600090815260208190526040902054610196565b3480156101d257600080fd5b50610196600160fd1b81565b3480156101ea57600080fd5b506101966101f9366004610845565b6001600160a01b031660009081526020819052604090205490565b34801561022057600080fd5b506100fe61022f366004610860565b6104de565b34801561024057600080fd5b506100fe61024f36600461088a565b610560565b34801561026057600080fd5b5061027461026f3660046108e3565b610575565b6040519015158152602001610160565b34801561029057600080fd5b506100fe61029f3660046108fc565b610597565b3480156102b057600080fd5b50610196600160ff1b81565b3480156102c857600080fd5b506102746102d73660046108fc565b61061c565b3480156102e857600080fd5b506001546102fc906001600160a01b031681565b6040516001600160a01b039091168152602001610160565b34801561032057600080fd5b506100fe61032f3660046108e3565b610645565b34801561034057600080fd5b5061027461034f3660046108e3565b610652565b6020810151815160609190156103f0576001600160e01b03198116600090815260026020526040812054908190036103c95760405162461bcd60e51b81526020600482015260136024820152721858d8d95cdcc81c9bdb19481b9bdd081cd95d606a1b60448201526064015b60405180910390fd5b6103d281610652565b6103ee5760405162461bcd60e51b81526004016103c090610918565b505b60015460405160009182916001600160a01b0390911690349061041490889061093f565b60006040518083038185875af1925050503d8060008114610451576040519150601f19603f3d011682016040523d82523d6000602084013e610456565b606091505b50915091508161049b5760405162461bcd60e51b815260206004820152601060248201526f195e1958dd5d1a5bdb8819985a5b195960821b60448201526064016103c0565b7f57a62eca76fc623c92f161d2a4b851851ece707135ce2af1eec256d660571b6d8386836040516104ce9392919061095b565b60405180910390a1949350505050565b6104eb600160fd1b610652565b6105075760405162461bcd60e51b81526004016103c090610918565b6001600160e01b03198216600081815260026020908152604091829020849055815192835282018390527fdb8ed917742b49e83acd1322bcaa8f18b1e5f78a70784c43ea14db7ab50e628d910160405180910390a15050565b6105718280519060200120826104de565b5050565b30600090815260208190526040812054610591905b8316831490565b92915050565b6105a4600160ff1b610652565b6105c05760405162461bcd60e51b81526004016103c090610918565b6105718282610617336105e8876001600160a01b031660009081526020819052604090205490565b6001600160a01b0391909116600090815260208190526040902054600019808818821618908716919091171690565b61065e565b6001600160a01b03821660009081526020819052604081205461063e9061058a565b9392505050565b61064f3082610597565b50565b6000610591338361061c565b6001600160a01b0383166000818152602081815260409182902084905581518581529081018490527fe9be537308880e0f56b7d7cfd7abf85f14c4934486d138f848b92a0cbaf659b4910160405180910390a2505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156106e7576106e76106b6565b604051601f8501601f19908116603f0116810190828211818310171561070f5761070f6106b6565b8160405280935085815286868601111561072857600080fd5b858560208301376000602087830101525050509392505050565b60006020828403121561075457600080fd5b813567ffffffffffffffff81111561076b57600080fd5b8201601f8101841361077c57600080fd5b61078b848235602084016106cc565b949350505050565b60005b838110156107ae578181015183820152602001610796565b50506000910152565b600081518084526107cf816020860160208601610793565b601f01601f19169290920160200192915050565b60208152600061063e60208301846107b7565b80356001600160e01b03198116811461080e57600080fd5b919050565b60006020828403121561082557600080fd5b61063e826107f6565b80356001600160a01b038116811461080e57600080fd5b60006020828403121561085757600080fd5b61063e8261082e565b6000806040838503121561087357600080fd5b61087c836107f6565b946020939093013593505050565b6000806040838503121561089d57600080fd5b823567ffffffffffffffff8111156108b457600080fd5b8301601f810185136108c557600080fd5b6108d4858235602084016106cc565b95602094909401359450505050565b6000602082840312156108f557600080fd5b5035919050565b6000806040838503121561090f57600080fd5b61087c8361082e565b6020808252600d908201526c1858d8d95cdcc819195b9a5959609a1b604082015260600190565b60008251610951818460208701610793565b9190910192915050565b63ffffffff60e01b8416815260606020820152600061097d60608301856107b7565b828103604084015261098f81856107b7565b969550505050505056fea26469706673582212206993ad950cca82a01e8e72c0503e3a006930148e125b67ad2894063853f6078264736f6c63430008150033a26469706673582212202a1a609a49d984f2d2e0a8326ec01d7930e4a3a728bb430cf69248ad2641e5a464736f6c63430008150033",
64
+ "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80635020380814610030575b600080fd5b61004361003e3660046101c9565b61005f565b6040516001600160a01b03909116815260200160405180910390f35b6000336001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156100ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100cf91906101ed565b6001600160a01b0316146101185760405162461bcd60e51b815260206004820152600c60248201526b3737ba1030b71037bbb732b960a11b604482015260640160405180910390fd5b60008233604051610128906101a4565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801561015b573d6000803e3d6000fd5b509050826001600160a01b0316816001600160a01b03167f480c2ac1e89311d31b5f348c0934382be45d3bb75dfe35f2f209652fed1505b360405160405180910390a392915050565b610b408061020b83390190565b6001600160a01b03811681146101c657600080fd5b50565b6000602082840312156101db57600080fd5b81356101e6816101b1565b9392505050565b6000602082840312156101ff57600080fd5b81516101e6816101b156fe608060405234801561001057600080fd5b50604051610b40380380610b4083398101604081905261002f9161012f565b80600061003f82600019806100bb565b61004a3082806100bb565b50506001600160a01b0382166100955760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b604482015260640160405180910390fd5b50600180546001600160a01b0319166001600160a01b0392909216919091179055610162565b6001600160a01b0383166000818152602081815260409182902084905581518581529081018490527fe9be537308880e0f56b7d7cfd7abf85f14c4934486d138f848b92a0cbaf659b4910160405180910390a2505050565b80516001600160a01b038116811461012a57600080fd5b919050565b6000806040838503121561014257600080fd5b61014b83610113565b915061015960208401610113565b90509250929050565b6109cf806101716000396000f3fe6080604052600436106100e15760003560e01c8063725f36261161007f578063c688d69311610059578063c688d693146102bc578063d4b83992146102dc578063d5bb7f6714610314578063fcc2c0781461033457610100565b8063725f362614610254578063ae5b102e14610284578063ae682e2e146102a457610100565b806334e48c9e116100bb57806334e48c9e146101c657806344276733146101de578063491d2611146102145780635defb40d1461023457610100565b806309c5eabe146101405780630e82fe25146101695780632b521416146101a457610100565b36610100576100fe60405180602001604052806000815250610354565b005b6100fe6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061035492505050565b61015361014e366004610742565b610354565b60405161016091906107e3565b60405180910390f35b34801561017557600080fd5b50610196610184366004610813565b60026020526000908152604090205481565b604051908152602001610160565b3480156101b057600080fd5b5030600090815260208190526040902054610196565b3480156101d257600080fd5b50610196600160fd1b81565b3480156101ea57600080fd5b506101966101f9366004610845565b6001600160a01b031660009081526020819052604090205490565b34801561022057600080fd5b506100fe61022f366004610860565b6104de565b34801561024057600080fd5b506100fe61024f36600461088a565b610560565b34801561026057600080fd5b5061027461026f3660046108e3565b610575565b6040519015158152602001610160565b34801561029057600080fd5b506100fe61029f3660046108fc565b610597565b3480156102b057600080fd5b50610196600160ff1b81565b3480156102c857600080fd5b506102746102d73660046108fc565b61061c565b3480156102e857600080fd5b506001546102fc906001600160a01b031681565b6040516001600160a01b039091168152602001610160565b34801561032057600080fd5b506100fe61032f3660046108e3565b610645565b34801561034057600080fd5b5061027461034f3660046108e3565b610652565b6020810151815160609190156103f0576001600160e01b03198116600090815260026020526040812054908190036103c95760405162461bcd60e51b81526020600482015260136024820152721858d8d95cdcc81c9bdb19481b9bdd081cd95d606a1b60448201526064015b60405180910390fd5b6103d281610652565b6103ee5760405162461bcd60e51b81526004016103c090610918565b505b60015460405160009182916001600160a01b0390911690349061041490889061093f565b60006040518083038185875af1925050503d8060008114610451576040519150601f19603f3d011682016040523d82523d6000602084013e610456565b606091505b50915091508161049b5760405162461bcd60e51b815260206004820152601060248201526f195e1958dd5d1a5bdb8819985a5b195960821b60448201526064016103c0565b7f57a62eca76fc623c92f161d2a4b851851ece707135ce2af1eec256d660571b6d8386836040516104ce9392919061095b565b60405180910390a1949350505050565b6104eb600160fd1b610652565b6105075760405162461bcd60e51b81526004016103c090610918565b6001600160e01b03198216600081815260026020908152604091829020849055815192835282018390527fdb8ed917742b49e83acd1322bcaa8f18b1e5f78a70784c43ea14db7ab50e628d910160405180910390a15050565b6105718280519060200120826104de565b5050565b30600090815260208190526040812054610591905b8316831490565b92915050565b6105a4600160ff1b610652565b6105c05760405162461bcd60e51b81526004016103c090610918565b6105718282610617336105e8876001600160a01b031660009081526020819052604090205490565b6001600160a01b0391909116600090815260208190526040902054600019808818821618908716919091171690565b61065e565b6001600160a01b03821660009081526020819052604081205461063e9061058a565b9392505050565b61064f3082610597565b50565b6000610591338361061c565b6001600160a01b0383166000818152602081815260409182902084905581518581529081018490527fe9be537308880e0f56b7d7cfd7abf85f14c4934486d138f848b92a0cbaf659b4910160405180910390a2505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156106e7576106e76106b6565b604051601f8501601f19908116603f0116810190828211818310171561070f5761070f6106b6565b8160405280935085815286868601111561072857600080fd5b858560208301376000602087830101525050509392505050565b60006020828403121561075457600080fd5b813567ffffffffffffffff81111561076b57600080fd5b8201601f8101841361077c57600080fd5b61078b848235602084016106cc565b949350505050565b60005b838110156107ae578181015183820152602001610796565b50506000910152565b600081518084526107cf816020860160208601610793565b601f01601f19169290920160200192915050565b60208152600061063e60208301846107b7565b80356001600160e01b03198116811461080e57600080fd5b919050565b60006020828403121561082557600080fd5b61063e826107f6565b80356001600160a01b038116811461080e57600080fd5b60006020828403121561085757600080fd5b61063e8261082e565b6000806040838503121561087357600080fd5b61087c836107f6565b946020939093013593505050565b6000806040838503121561089d57600080fd5b823567ffffffffffffffff8111156108b457600080fd5b8301601f810185136108c557600080fd5b6108d4858235602084016106cc565b95602094909401359450505050565b6000602082840312156108f557600080fd5b5035919050565b6000806040838503121561090f57600080fd5b61087c8361082e565b6020808252600d908201526c1858d8d95cdcc819195b9a5959609a1b604082015260600190565b60008251610951818460208701610793565b9190910192915050565b63ffffffff60e01b8416815260606020820152600061097d60608301856107b7565b828103604084015261098f81856107b7565b969550505050505056fea26469706673582212206993ad950cca82a01e8e72c0503e3a006930148e125b67ad2894063853f6078264736f6c63430008150033a26469706673582212202a1a609a49d984f2d2e0a8326ec01d7930e4a3a728bb430cf69248ad2641e5a464736f6c63430008150033",
65
+ "devdoc": {
66
+ "author": "Basil Gorin",
67
+ "events": {
68
+ "NewOwnableToAccessControlAdapterDeployed(address,address)": {
69
+ "details": "Fired in deployNewOwnableToAccessControlAdapter",
70
+ "params": {
71
+ "adapterAddress": "newly deployed OwnableToAccessControlAdapter address",
72
+ "ownableTargetAddress": "OZ Ownable target contract address"
73
+ }
74
+ }
75
+ },
76
+ "kind": "dev",
77
+ "methods": {
78
+ "deployNewOwnableToAccessControlAdapter(address)": {
79
+ "params": {
80
+ "targetAddress": "OZ Ownable target address to bind OwnableToAccessControlAdapter to"
81
+ },
82
+ "returns": {
83
+ "_0": "address of the newly deployed OwnableToAccessControlAdapter contract"
84
+ }
85
+ }
86
+ },
87
+ "title": "Adapter Factory",
88
+ "version": 1
89
+ },
90
+ "userdoc": {
91
+ "kind": "user",
92
+ "methods": {
93
+ "deployNewOwnableToAccessControlAdapter(address)": {
94
+ "notice": "Deploys new OwnableToAccessControlAdapter bound to the OZ Ownable contract specified. Can be executed only by the OZ Ownable target owner. This owner is expected to transfer the ownership to the newly deployed OwnableToAccessControlAdapter contract address."
95
+ }
96
+ },
97
+ "notice": "Helper contract simplifying the deployment of the OwnableToAccessControlAdapter",
98
+ "version": 1
99
+ },
100
+ "storageLayout": {
101
+ "storage": [],
102
+ "types": null
103
+ }
104
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "language": "Solidity",
3
+ "sources": {
4
+ "contracts/AccessControl.sol": {
5
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22; // require with message (0.4.22), pure/view modifiers (0.4.16), hardhat (0.4.11)\n\n/**\n * @title Role-based Access Control (RBAC)\n *\n * @notice Access control smart contract provides an API to check\n * if a specific operation is permitted globally and/or\n * if a particular user has a permission to execute it.\n *\n * @notice This contract is inherited by other contracts requiring the role-based access control (RBAC)\n * protection for the restricted access functions\n *\n * @notice It deals with two main entities: features and roles.\n *\n * @notice Features are designed to be used to enable/disable public functions\n * of the smart contract (used by a wide audience).\n * @notice User roles are designed to control the access to restricted functions\n * of the smart contract (used by a limited set of maintainers).\n *\n * @notice Terms \"role\", \"permissions\" and \"set of permissions\" have equal meaning\n * in the documentation text and may be used interchangeably.\n * @notice Terms \"permission\", \"single permission\" implies only one permission bit set.\n *\n * @notice Access manager is a special role which allows to grant/revoke other roles.\n * Access managers can only grant/revoke permissions which they have themselves.\n * As an example, access manager with no other roles set can only grant/revoke its own\n * access manager permission and nothing else.\n *\n * @notice Access manager permission should be treated carefully, as a super admin permission:\n * Access manager with even no other permission can interfere with another account by\n * granting own access manager permission to it and effectively creating more powerful\n * permission set than its own.\n *\n * @dev Both current and OpenZeppelin AccessControl implementations feature a similar API\n * to check/know \"who is allowed to do this thing\".\n * @dev Zeppelin implementation is more flexible:\n * - it allows setting unlimited number of roles, while current is limited to 256 different roles\n * - it allows setting an admin for each role, while current allows having only one global admin\n * @dev Current implementation is more lightweight:\n * - it uses only 1 bit per role, while Zeppelin uses 256 bits\n * - it allows setting up to 256 roles at once, in a single transaction, while Zeppelin allows\n * setting only one role in a single transaction\n *\n * @dev This smart contract is designed to be inherited by other\n * smart contracts which require access control management capabilities.\n *\n * @dev Access manager permission has a bit 255 set.\n * This bit must not be used by inheriting contracts for any other permissions/features.\n *\n * @author Basil Gorin\n */\nabstract contract AccessControl {\n\t/**\n\t * @dev Privileged addresses with defined roles/permissions\n\t * @dev In the context of ERC20/ERC721 tokens these can be permissions to\n\t * allow minting or burning tokens, transferring on behalf and so on\n\t *\n\t * @dev Maps user address to the permissions bitmask (role), where each bit\n\t * represents a permission\n\t * @dev Bitmask 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n\t * represents all possible permissions\n\t * @dev 'This' address mapping represents global features of the smart contract\n\t *\n\t * @dev We keep the mapping private to prevent direct writes to it from the inheriting\n\t * contracts, `getRole()` and `updateRole()` functions should be used instead\n\t */\n\tmapping(address => uint256) private userRoles;\n\n\t/**\n\t * @notice Access manager is responsible for assigning the roles to users,\n\t * enabling/disabling global features of the smart contract\n\t * @notice Access manager can add, remove and update user roles,\n\t * remove and update global features\n\t *\n\t * @dev Role ROLE_ACCESS_MANAGER allows modifying user roles and global features\n\t * @dev Role ROLE_ACCESS_MANAGER has single bit at position 255 enabled\n\t */\n\tuint256 public constant ROLE_ACCESS_MANAGER = 0x8000000000000000000000000000000000000000000000000000000000000000;\n\n\t/**\n\t * @dev Bitmask representing all the possible permissions (super admin role)\n\t * @dev Has all the bits are enabled (2^256 - 1 value)\n\t */\n\tuint256 internal constant FULL_PRIVILEGES_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;\n\n\t/**\n\t * @dev Fired in updateRole() and updateFeatures()\n\t *\n\t * @param operator address which was granted/revoked permissions\n\t * @param requested permissions requested\n\t * @param assigned permissions effectively set\n\t */\n\tevent RoleUpdated(address indexed operator, uint256 requested, uint256 assigned);\n\n\t/**\n\t * @notice Function modifier making a function defined as public behave as restricted\n\t * (so that only a pre-configured set of accounts can execute it)\n\t *\n\t * @param role the role transaction executor is required to have;\n\t * the function throws an \"access denied\" exception if this condition is not met\n\t */\n\tmodifier restrictedTo(uint256 role) {\n\t\t// verify the access permission\n\t\trequire(isSenderInRole(role), \"access denied\");\n\n\t\t// execute the rest of the function\n\t\t_;\n\t}\n\n\t/**\n\t * @notice Creates an access control instance, setting the contract owner to have full privileges\n\t *\n\t * @param _owner smart contract owner having full privileges, can be zero\n\t * @param _features initial features mask of the contract, can be zero\n\t */\n\tconstructor(address _owner, uint256 _features) internal { // visibility modifier is required to be compilable with 0.6.x\n\t\t// grant owner full privileges\n\t\t__setRole(_owner, FULL_PRIVILEGES_MASK, FULL_PRIVILEGES_MASK);\n\t\t// update initial features bitmask\n\t\t__setRole(address(this), _features, _features);\n\t}\n\n\t/**\n\t * @notice Retrieves globally set of features enabled\n\t *\n\t * @dev Effectively reads userRoles role for the contract itself\n\t *\n\t * @return 256-bit bitmask of the features enabled\n\t */\n\tfunction features() public view returns (uint256) {\n\t\t// features are stored in 'this' address mapping of `userRoles`\n\t\treturn getRole(address(this));\n\t}\n\n\t/**\n\t * @notice Updates set of the globally enabled features (`features`),\n\t * taking into account sender's permissions\n\t *\n\t * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission\n\t * @dev Function is left for backward compatibility with older versions\n\t *\n\t * @param _mask bitmask representing a set of features to enable/disable\n\t */\n\tfunction updateFeatures(uint256 _mask) public {\n\t\t// delegate call to `updateRole`\n\t\tupdateRole(address(this), _mask);\n\t}\n\n\t/**\n\t * @notice Reads the permissions (role) for a given user from the `userRoles` mapping\n\t * (privileged addresses with defined roles/permissions)\n\t * @notice In the context of ERC20/ERC721 tokens these can be permissions to\n\t * allow minting or burning tokens, transferring on behalf and so on\n\t *\n\t * @dev Having a simple getter instead of making the mapping public\n\t * allows enforcing the encapsulation of the mapping and protects from\n\t * writing to it directly in the inheriting smart contracts\n\t *\n\t * @param operator address of a user to read permissions for,\n\t * or self address to read global features of the smart contract\n\t */\n\tfunction getRole(address operator) public view returns(uint256) {\n\t\t// read the value from `userRoles` and return\n\t\treturn userRoles[operator];\n\t}\n\n\t/**\n\t * @notice Updates set of permissions (role) for a given user,\n\t * taking into account sender's permissions.\n\t *\n\t * @dev Setting role to zero is equivalent to removing an all permissions\n\t * @dev Setting role to `FULL_PRIVILEGES_MASK` is equivalent to\n\t * copying senders' permissions (role) to the user\n\t * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission\n\t *\n\t * @param operator address of a user to alter permissions for,\n\t * or self address to alter global features of the smart contract\n\t * @param role bitmask representing a set of permissions to\n\t * enable/disable for a user specified\n\t */\n\tfunction updateRole(address operator, uint256 role) public {\n\t\t// caller must have a permission to update user roles\n\t\trequire(isSenderInRole(ROLE_ACCESS_MANAGER), \"access denied\");\n\n\t\t// evaluate the role and reassign it\n\t\t__setRole(operator, role, _evaluateBy(msg.sender, getRole(operator), role));\n\t}\n\n\t/**\n\t * @notice Determines the permission bitmask an operator can set on the\n\t * target permission set\n\t * @notice Used to calculate the permission bitmask to be set when requested\n\t * in `updateRole` and `updateFeatures` functions\n\t *\n\t * @dev Calculated based on:\n\t * 1) operator's own permission set read from userRoles[operator]\n\t * 2) target permission set - what is already set on the target\n\t * 3) desired permission set - what do we want set target to\n\t *\n\t * @dev Corner cases:\n\t * 1) Operator is super admin and its permission set is `FULL_PRIVILEGES_MASK`:\n\t * `desired` bitset is returned regardless of the `target` permission set value\n\t * (what operator sets is what they get)\n\t * 2) Operator with no permissions (zero bitset):\n\t * `target` bitset is returned regardless of the `desired` value\n\t * (operator has no authority and cannot modify anything)\n\t *\n\t * @dev Example:\n\t * Consider an operator with the permissions bitmask 00001111\n\t * is about to modify the target permission set 01010101\n\t * Operator wants to set that permission set to 00110011\n\t * Based on their role, an operator has the permissions\n\t * to update only lowest 4 bits on the target, meaning that\n\t * high 4 bits of the target set in this example is left\n\t * unchanged and low 4 bits get changed as desired: 01010011\n\t *\n\t * @param operator address of the contract operator which is about to set the permissions\n\t * @param target input set of permissions to operator is going to modify\n\t * @param desired desired set of permissions operator would like to set\n\t * @return resulting set of permissions given operator will set\n\t */\n\tfunction _evaluateBy(address operator, uint256 target, uint256 desired) internal view returns (uint256) {\n\t\t// read operator's permissions\n\t\tuint256 p = getRole(operator);\n\n\t\t// taking into account operator's permissions,\n\t\t// 1) enable the permissions desired on the `target`\n\t\ttarget |= p & desired;\n\t\t// 2) disable the permissions desired on the `target`\n\t\ttarget &= FULL_PRIVILEGES_MASK ^ (p & (FULL_PRIVILEGES_MASK ^ desired));\n\n\t\t// return calculated result\n\t\treturn target;\n\t}\n\n\t/**\n\t * @notice Checks if requested set of features is enabled globally on the contract\n\t *\n\t * @param required set of features to check against\n\t * @return true if all the features requested are enabled, false otherwise\n\t */\n\tfunction isFeatureEnabled(uint256 required) public view returns (bool) {\n\t\t// delegate call to `__hasRole`, passing `features` property\n\t\treturn __hasRole(features(), required);\n\t}\n\n\t/**\n\t * @notice Checks if transaction sender `msg.sender` has all the permissions required\n\t *\n\t * @param required set of permissions (role) to check against\n\t * @return true if all the permissions requested are enabled, false otherwise\n\t */\n\tfunction isSenderInRole(uint256 required) public view returns (bool) {\n\t\t// delegate call to `isOperatorInRole`, passing transaction sender\n\t\treturn isOperatorInRole(msg.sender, required);\n\t}\n\n\t/**\n\t * @notice Checks if operator has all the permissions (role) required\n\t *\n\t * @param operator address of the user to check role for\n\t * @param required set of permissions (role) to check\n\t * @return true if all the permissions requested are enabled, false otherwise\n\t */\n\tfunction isOperatorInRole(address operator, uint256 required) public view returns (bool) {\n\t\t// delegate call to `__hasRole`, passing operator's permissions (role)\n\t\treturn __hasRole(getRole(operator), required);\n\t}\n\n\t/**\n\t * @dev Sets the `assignedRole` role to the operator, logs both `requestedRole` and `actualRole`\n\t *\n\t * @dev Unsafe:\n\t * provides direct write access to `userRoles` mapping without any security checks,\n\t * doesn't verify the executor (msg.sender) permissions,\n\t * must be kept private at all times\n\t *\n\t * @param operator address of a user to alter permissions for,\n\t * or self address to alter global features of the smart contract\n\t * @param requestedRole bitmask representing a set of permissions requested\n\t * to be enabled/disabled for a user specified, used only to be logged into event\n\t * @param assignedRole bitmask representing a set of permissions to\n\t * enable/disable for a user specified, used to update the mapping and to be logged into event\n\t */\n\tfunction __setRole(address operator, uint256 requestedRole, uint256 assignedRole) private {\n\t\t// assign the role to the operator\n\t\tuserRoles[operator] = assignedRole;\n\n\t\t// fire an event\n\t\temit RoleUpdated(operator, requestedRole, assignedRole);\n\t}\n\n\t/**\n\t * @dev Checks if role `actual` contains all the permissions required `required`\n\t *\n\t * @param actual existent role\n\t * @param required required role\n\t * @return true if actual has required role (all permissions), false otherwise\n\t */\n\tfunction __hasRole(uint256 actual, uint256 required) private pure returns (bool) {\n\t\t// check the bitmask for the role required and return the result\n\t\treturn actual & required == required;\n\t}\n}\n"
6
+ },
7
+ "contracts/AdapterFactory.sol": {
8
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\nimport \"./OwnableToAccessControlAdapter.sol\";\n\n/**\n * @notice Ownable is a contract which is aware of its owner, that is has owner() function\n */\ninterface Ownable {\n\t/**\n\t * @notice Smart contract owner\n\t *\n\t * @return the address of the smart contract owner\n\t */\n\tfunction owner() external returns(address);\n}\n\n/**\n * @title Adapter Factory\n *\n * @notice Helper contract simplifying the deployment of the OwnableToAccessControlAdapter\n *\n * @author Basil Gorin\n */\ncontract AdapterFactory {\n\t/**\n\t * @dev Fired in deployNewOwnableToAccessControlAdapter\n\t *\n\t * @param adapterAddress newly deployed OwnableToAccessControlAdapter address\n\t * @param ownableTargetAddress OZ Ownable target contract address\n\t */\n\tevent NewOwnableToAccessControlAdapterDeployed(address indexed adapterAddress, address indexed ownableTargetAddress);\n\n\t/**\n\t * @notice Deploys new OwnableToAccessControlAdapter bound to the OZ Ownable contract specified.\n\t * Can be executed only by the OZ Ownable target owner. This owner is expected to transfer\n\t * the ownership to the newly deployed OwnableToAccessControlAdapter contract address.\n\t *\n\t * @param targetAddress OZ Ownable target address to bind OwnableToAccessControlAdapter to\n\t * @return address of the newly deployed OwnableToAccessControlAdapter contract\n\t */\n\tfunction deployNewOwnableToAccessControlAdapter(address targetAddress) public returns(address) {\n\t\t// verify sender is a target owner\n\t\trequire(Ownable(targetAddress).owner() == msg.sender, \"not an owner\");\n\n\t\t// deploy the OwnableToAccessControlAdapter\n\t\t// and set its ownership immediately to the tx executor (msg.sender)\n\t\taddress adapterAddress = address(new OwnableToAccessControlAdapter(targetAddress, msg.sender));\n\n\t\t// emit an event\n\t\temit NewOwnableToAccessControlAdapterDeployed(adapterAddress, targetAddress);\n\n\t\t// return address of the newly deployed OwnableToAccessControlAdapter contract\n\t\treturn adapterAddress;\n\t}\n}\n"
9
+ },
10
+ "contracts/mocks/AccessControlMock.sol": {
11
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22;\n\nimport \"../AccessControl.sol\";\n\n// Used in AccessControl tests to check if `isSenderInRole` works through the `restrictedTo` modifier\ncontract AccessControlMock is AccessControl {\n\tuint32 public constant RESTRICTED_ROLE = 1;\n\tevent Restricted();\n\tconstructor(address _owner, uint256 _features) AccessControl(_owner, _features){}\n\tfunction restricted() public restrictedTo(RESTRICTED_ROLE) {\n\t\temit Restricted();\n\t}\n}\n"
12
+ },
13
+ "contracts/OwnableToAccessControlAdapter.sol": {
14
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2; // breaking changes in .call() (0.5.0), allow .call{}() (0.6.2)\n\nimport \"./AccessControl.sol\";\n\n/**\n * @title OZ Ownable to AccessControl Adapter (short: AccessControl Adapter)\n *\n * @notice Helper contract allowing to change the access model of the already deployed\n * OpenZeppelin Ownable contract to the AccessControl model\n *\n * @dev Installation Flow\n * Prerequisite: deployed OZ Ownable contract (target contract) address (target_address)\n *\n * 1. Deploy the AccessControl Adapter bound to the already deployed OZ Ownable contract\n * (specify the target OZ Ownable contract address in the constructor upon the deployment)\n *\n * const adapter = await (artifacts.require(\"OwnableToAccessControlAdapter\")).new(target_address);\n *\n * 2. Define what Ownable-restricted public functions on the target contract you'd like to be able\n * to provide access to through the adapter contract\n *\n * 3. Map every such function with the role required to execute it using `updateAccessRole()` function\n * For example, to be able to provide an access to the transferOwnership(address) function, you could do\n *\n * const ROLE_TRANSFER_OWNERSHIP_MANAGER = 0x00010000;\n * await adapter.updateAccessRole(\"transferOwnership(address)\", ROLE_TRANSFER_OWNERSHIP_MANAGER);\n *\n * 4. Provide the roles to the corresponding operators as you would usually do with AccessControl\n * For example, if you wish an address 0x00000000000000000000000000000000000Ff1CE to grant an access to the\n * transferOwnership(address) function on the target, you could do\n *\n * const operator = \"0x00000000000000000000000000000000000Ff1CE\";\n * await adapter.updateRole(operator, ROLE_TRANSFER_OWNERSHIP_MANAGER);\n *\n * 5. Transfer the ownership of the target contract to the deployed AccessControl Adapter contract\n * Note that you can also do steps 2-4 after the step 5\n *\n * @dev Usage Flow\n * Prerequisite: installed AccessControl Adapter with the access to at least one restricted target contract\n * function configured\n *\n * To execute the restricted access function on the target contract via the AccessControl Adapter\n * 1. Use target contract ABI to construct a low-level function call calldata\n * For example, to construct the transferOwnership() function calldata to transfer the ownership to the\n * 0x00000000000000000000000000000000DEAdc0De address, you could do\n *\n * const to = \"0x00000000000000000000000000000000DEAdc0De\";\n * const calldata = target.contract.methods.transferOwnership(to).encodeABI();\n *\n * 2. Execute a low-level function call on the AccessControl Adapter contract using the constructed calldata\n * For example, to execute the transferOwnership() function (prepared in step 1), you could do\n *\n * await web3.eth.sendTransaction({\n * from: operator,\n * to: adapter.address,\n * data: calldata,\n * }\n *\n * 3. It is also ok to add an ether to the transaction by adding a value field to the `sendTransaction` call,\n * as well as sending plain ether transfer transaction, as long as target contract has payable functions,\n * and/or has a default payable receiver\n *\n * @author Basil Gorin\n */\ncontract OwnableToAccessControlAdapter is AccessControl {\n\t/**\n\t * @dev Target OZ Ownable contract AccessControl Adapter executes the transactions on\n\t *\n\t * @dev Target contract must transfer its ownership to the AccessControl Adapter\n\t */\n\taddress public target;\n\n\t/**\n\t * @dev Access roles mapping stores the roles required to access the functions on the\n\t * target contract, guarding it from the unauthorized access\n\t *\n\t * @dev Maps function selector (bytes4) on the target contract to the access role (permission)\n\t * required to execute the function\n\t */\n\tmapping(bytes4 => uint256) public accessRoles;\n\n\t/**\n\t * @notice Access Roles manager is responsible for assigning the access roles to functions\n\t *\n\t * @dev Role ROLE_ACCESS_MANAGER allows modifying `accessRoles` mapping\n\t */\n\tuint256 public constant ROLE_ACCESS_ROLES_MANAGER = 0x2000000000000000000000000000000000000000000000000000000000000000;\n\n\t/**\n\t * @dev Fired in `updateAccessRole` when the `accessRoles` mapping is updated\n\t *\n\t * @param selector selector of the function which corresponding access role was updated\n\t * @param role effective required role to execute the function defined by the selector\n\t */\n\tevent AccessRoleUpdated(bytes4 selector, uint256 role);\n\n\t/**\n\t * @dev Logs function execution result on the target if the execution completed successfully\n\t *\n\t * @param selector selector of the function which was executed on the target contract\n\t * @param data full calldata payload passed to the target contract (includes the 4-bytes selector)\n\t * @param result execution response from the target contract\n\t */\n\tevent ExecutionComplete(bytes4 selector, bytes data, bytes result);\n\n\t/**\n\t * @dev Deploys an AccessControl Adapter binding it to the target OZ Ownable contract,\n\t * and setting the ownership of the adapter itself to the deployer\n\t *\n\t * @param _target target OZ Ownable contract address\n\t * @param _owner smart contract owner having full privileges\n\t */\n\tconstructor(address _target, address _owner) public AccessControl(_owner, 0) {\n\t\t// verify the inputs\n\t\trequire(_target != address(0), \"zero address\");\n\n\t\t// initialize internal contract state\n\t\ttarget = _target;\n\t}\n\n\t/**\n\t * @dev Updates the access role required to execute the function defined by its signature\n\t * on the target contract\n\t *\n\t * @dev More on function signatures and selectors: https://docs.soliditylang.org/en/develop/abi-spec.html\n\t *\n\t * @param signature function signature on the target contract, for example\n\t * \"transferOwnership(address)\"\n\t * @param role role required to execute this function, or zero to disable\n\t * access to the specified function for everyone\n\t */\n\tfunction updateAccessRole(string memory signature, uint256 role) public {\n\t\t// delegate to `updateAccessRole(bytes4, uint256)`\n\t\tupdateAccessRole(bytes4(keccak256(bytes(signature))), role);\n\t}\n\n\t/**\n\t * @dev Updates the access role required to execute the function defined by its selector\n\t * on the target contract\n\t *\n\t * @dev More on function signatures and selectors: https://docs.soliditylang.org/en/develop/abi-spec.html\n\t *\n\t * @param selector function selector on the target contract, for example\n\t * 0xf2fde38b selector corresponds to the \"transferOwnership(address)\" function\n\t * @param role role required to execute this function, or zero to disable\n\t * access to the specified function for everyone\n\t */\n\tfunction updateAccessRole(bytes4 selector, uint256 role) public {\n\t\t// verify the access permission\n\t\trequire(isSenderInRole(ROLE_ACCESS_ROLES_MANAGER), \"access denied\");\n\n\t\t// update the function access role\n\t\taccessRoles[selector] = role;\n\n\t\t// emit an event\n\t\temit AccessRoleUpdated(selector, role);\n\t}\n\n\t/**\n\t * @dev Low-level execute of the data calldata on the target contract\n\t *\n\t * @dev This function extracts the target function selector from the calldata specified\n\t * and verifies transaction executor permission to access the function on the target\n\t * using the `accessRoles` mapping\n\t *\n\t * @dev Throws if there is no `accessRoles` mapping configured for the function\n\t * @dev Throws if transaction executor role doesn't contain the required role from `accessRoles` mapping\n\t * @dev Throws if execution on the target returns an error\n\t *\n\t * @param data low-level calldata to be passed as is to the target contract for the execution\n\t * @return the response from the target contract after the successful execution\n\t */\n\tfunction execute(bytes memory data) public payable returns(bytes memory) {\n\t\t// extract the selector (first 4 bytes as bytes4) using assembly\n\t\tbytes4 selector;\n\t\tassembly {\n\t\t\t// load the first word after the length field\n\t\t\tselector := mload(add(data, 32))\n\t\t}\n\n\t\t// zero data length means we're trying to execute the receive() function on\n\t\t// the target and supply some ether to the target; in this case we don't need a security check\n\t\t// if the data is present, we're executing some real function and must do a security check\n\t\tif(data.length != 0) {\n\t\t\t// determine the role required to access the function\n\t\t\tuint256 roleRequired = accessRoles[selector];\n\n\t\t\t// verify function access role was already set\n\t\t\trequire(roleRequired != 0, \"access role not set\");\n\n\t\t\t// verify the access permission\n\t\t\trequire(isSenderInRole(roleRequired), \"access denied\");\n\t\t}\n\n\t\t// execute the call on the target\n\t\t(bool success, bytes memory result) = address(target).call{value: msg.value}(data);\n\n\t\t// verify the execution completed successfully\n\t\trequire(success, \"execution failed\");\n\n\t\t// emit an event\n\t\temit ExecutionComplete(selector, data, result);\n\n\t\t// return the result\n\t\treturn result;\n\t}\n\n\t/**\n\t * @dev Proxies the ether sent to the AccessControl Adapter to the target contract\n\t *\n\t * @dev Throws if target contract doesn't have the default payable receiver, i.e. doesn't accept ether\n\t */\n\treceive() external payable {\n\t\t// delegate to `execute(bytes)`\n\t\texecute(bytes(\"\"));\n\t}\n\n\t/**\n\t * @dev Calls the target contract with the calldata specified in the transaction\n\t *\n\t * @dev See `execute()` function for details\n\t * @dev Use `execute()` function directly if the target contract function signature collides\n\t * with any of the AccessControl Adapter functions signature\n\t */\n\tfallback() external payable {\n\t\t// msg.data contains full calldata: function selector + encoded function arguments (if any)\n\t\t// delegate to `execute(bytes)`\n\t\texecute(msg.data);\n\t}\n}\n"
15
+ }
16
+ },
17
+ "settings": {
18
+ "optimizer": {
19
+ "enabled": true,
20
+ "runs": 200
21
+ },
22
+ "evmVersion": "paris",
23
+ "outputSelection": {
24
+ "*": {
25
+ "*": [
26
+ "abi",
27
+ "evm.bytecode",
28
+ "evm.deployedBytecode",
29
+ "evm.methodIdentifiers",
30
+ "metadata",
31
+ "devdoc",
32
+ "userdoc",
33
+ "storageLayout",
34
+ "evm.gasEstimates"
35
+ ],
36
+ "": [
37
+ "ast"
38
+ ]
39
+ }
40
+ },
41
+ "metadata": {
42
+ "useLiteralContent": true
43
+ }
44
+ }
45
+ }
package/hardhat.config.js CHANGED
@@ -21,6 +21,10 @@
21
21
  * or
22
22
  * - MNEMONIC5 – goerli mnemonic, 12 words
23
23
  *
24
+ * - P_KEY11155111 – sepolia private key, should start with 0x
25
+ * or
26
+ * - MNEMONIC11155111 – sepolia mnemonic, 12 words
27
+ *
24
28
  * - P_KEY137 – polygon/matic private key, should start with 0x
25
29
  * or
26
30
  * - MNEMONIC137 – polygon/matic mnemonic, 12 words
@@ -37,6 +41,18 @@
37
41
  * or
38
42
  * - MNEMONIC97 – Binance Smart Chain (BSC) testnet mnemonic, 12 words
39
43
  *
44
+ * - P_KEY8453 – Base Mainnet Optimistic Rollup (L2) private key, should start with 0x
45
+ * or
46
+ * - MNEMONIC8453 – Base Mainnet Optimistic Rollup (L2) mnemonic, 12 words
47
+ *
48
+ * - P_KEY84531 – Base Goerli (testnet) Optimistic Rollup (L2) private key, should start with 0x
49
+ * or
50
+ * - MNEMONIC84531 – Base Goerli (testnet) Optimistic Rollup (L2) mnemonic, 12 words
51
+ *
52
+ * - P_KEY84532 – Base Sepolia (testnet) Optimistic Rollup (L2) private key, should start with 0x
53
+ * or
54
+ * - MNEMONIC84532 – Base Sepolia (testnet) Optimistic Rollup (L2) mnemonic, 12 words
55
+ *
40
56
  * - ALCHEMY_KEY – Alchemy API key
41
57
  * or
42
58
  * - INFURA_KEY – Infura API key (Project ID)
@@ -47,6 +63,8 @@
47
63
  *
48
64
  * - BSCSCAN_KEY – BscScan API key
49
65
  *
66
+ * - BASESCAN_KEY – BaseScan API key
67
+ *
50
68
  * - REPORT_GAS - optional, set it to true to print gas usage info
51
69
  */
52
70
 
@@ -109,6 +127,14 @@ else if(process.env.P_KEY5 && !process.env.P_KEY5.startsWith("0x")) {
109
127
  console.warn("P_KEY5 doesn't start with 0x. Appended 0x");
110
128
  process.env.P_KEY5 = "0x" + process.env.P_KEY5;
111
129
  }
130
+ if(!process.env.MNEMONIC11155111 && !process.env.P_KEY11155111) {
131
+ console.warn("neither MNEMONIC11155111 nor P_KEY11155111 is not set. Sepolia deployments won't be available");
132
+ process.env.MNEMONIC11155111 = FAKE_MNEMONIC;
133
+ }
134
+ else if(process.env.P_KEY11155111 && !process.env.P_KEY11155111.startsWith("0x")) {
135
+ console.warn("P_KEY11155111 doesn't start with 0x. Appended 0x");
136
+ process.env.P_KEY11155111 = "0x" + process.env.P_KEY11155111;
137
+ }
112
138
  if(!process.env.MNEMONIC137 && !process.env.P_KEY137) {
113
139
  console.warn("neither MNEMONIC137 nor P_KEY137 is not set. Polygon mainnet deployments won't be available");
114
140
  process.env.MNEMONIC137 = FAKE_MNEMONIC;
@@ -141,6 +167,30 @@ else if(process.env.P_KEY97 && !process.env.P_KEY97.startsWith("0x")) {
141
167
  console.warn("P_KEY97 doesn't start with 0x. Appended 0x");
142
168
  process.env.P_KEY97 = "0x" + process.env.P_KEY97;
143
169
  }
170
+ if(!process.env.MNEMONIC8453 && !process.env.P_KEY8453) {
171
+ console.warn("neither MNEMONIC8453 nor P_KEY8453 is not set. Base Mainnet deployments won't be available");
172
+ process.env.MNEMONIC8453 = FAKE_MNEMONIC;
173
+ }
174
+ else if(process.env.P_KEY8453 && !process.env.P_KEY8453.startsWith("0x")) {
175
+ console.warn("P_KEY8453 doesn't start with 0x. Appended 0x");
176
+ process.env.P_KEY8453 = "0x" + process.env.P_KEY8453;
177
+ }
178
+ if(!process.env.MNEMONIC84531 && !process.env.P_KEY84531) {
179
+ console.warn("neither MNEMONIC84531 nor P_KEY84531 is not set. Base Goerli (testnet) deployments won't be available");
180
+ process.env.MNEMONIC84531 = FAKE_MNEMONIC;
181
+ }
182
+ else if(process.env.P_KEY84531 && !process.env.P_KEY84531.startsWith("0x")) {
183
+ console.warn("P_KEY84531 doesn't start with 0x. Appended 0x");
184
+ process.env.P_KEY84531 = "0x" + process.env.P_KEY84531;
185
+ }
186
+ if(!process.env.MNEMONIC84532 && !process.env.P_KEY84532) {
187
+ console.warn("neither MNEMONIC84532 nor P_KEY84532 is not set. Base Sepolia (testnet) deployments won't be available");
188
+ process.env.MNEMONIC84531 = FAKE_MNEMONIC;
189
+ }
190
+ else if(process.env.P_KEY84532 && !process.env.P_KEY84532.startsWith("0x")) {
191
+ console.warn("P_KEY84532 doesn't start with 0x. Appended 0x");
192
+ process.env.P_KEY84532 = "0x" + process.env.P_KEY84532;
193
+ }
144
194
  if(!process.env.INFURA_KEY && !process.env.ALCHEMY_KEY) {
145
195
  console.warn("neither INFURA_KEY nor ALCHEMY_KEY is not set. Deployments may not be available");
146
196
  process.env.INFURA_KEY = "";
@@ -158,6 +208,9 @@ if(!process.env.BSCSCAN_KEY) {
158
208
  console.warn("BSCSCAN_KEY is not set. Deployed smart contract code verification won't be available on BscScan");
159
209
  process.env.BSCSCAN_KEY = "";
160
210
  }
211
+ if(!process.env.BASESCAN_KEY) {
212
+ console.warn("BASESCAN_KEY is not set. Deployed smart contract code verification won't be available on BaseScan");
213
+ }
161
214
 
162
215
  /**
163
216
  * @type import('hardhat/config').HardhatUserConfig
@@ -208,28 +261,48 @@ module.exports = {
208
261
  url: get_endpoint_url("goerli"),
209
262
  accounts: get_accounts(process.env.P_KEY5, process.env.MNEMONIC5),
210
263
  },
264
+ // https://sepolia.etherscan.io/
265
+ sepolia: {
266
+ url: get_endpoint_url("sepolia"),
267
+ accounts: get_accounts(process.env.P_KEY11155111, process.env.MNEMONIC11155111),
268
+ },
211
269
  // matic/polygon L2 mainnet
212
270
  // https://polygonscan.com/
213
271
  polygon: {
214
- url: "https://polygon-rpc.com/",
272
+ url: get_endpoint_url("polygon"),
215
273
  accounts: get_accounts(process.env.P_KEY137, process.env.MNEMONIC137),
216
274
  },
217
275
  // matic/polygon L1 testnet – Mumbai
218
276
  // https://mumbai.polygonscan.com/
219
277
  mumbai: {
220
- url: "https://rpc-mumbai.maticvigil.com",
278
+ url: get_endpoint_url("mumbai"),
221
279
  accounts: get_accounts(process.env.P_KEY80001, process.env.MNEMONIC80001),
222
280
  },
223
281
  // Binance Smart Chain (BSC) L2 mainnet
224
282
  binance: {
225
- url: "https://bsc-dataseed1.binance.org/",
283
+ url: get_endpoint_url("binance"),
226
284
  accounts: get_accounts(process.env.P_KEY56, process.env.MNEMONIC56),
227
285
  },
228
286
  // Binance Smart Chain (BSC) L2 testnet
229
287
  binance_testnet: {
230
- url: "https://data-seed-prebsc-1-s3.binance.org:8545/",
288
+ url: get_endpoint_url("binance_testnet"),
231
289
  accounts: get_accounts(process.env.P_KEY97, process.env.MNEMONIC97),
232
290
  },
291
+ // Base Mainnet Optimistic Rollup (L2)
292
+ base_mainnet: {
293
+ url: get_endpoint_url("base_mainnet"),
294
+ accounts: get_accounts(process.env.P_KEY8453, process.env.MNEMONIC8453),
295
+ },
296
+ // Base Testnet Optimistic Rollup (L2)
297
+ base_goerli: {
298
+ url: get_endpoint_url("base_goerli"),
299
+ accounts: get_accounts(process.env.P_KEY84531, process.env.MNEMONIC84531),
300
+ },
301
+ // Base Testnet Optimistic Rollup (L2)
302
+ base_sepolia: {
303
+ url: get_endpoint_url("base_sepolia"),
304
+ accounts: get_accounts(process.env.P_KEY84532, process.env.MNEMONIC84532),
305
+ },
233
306
  },
234
307
 
235
308
  // Configure Solidity compiler
@@ -322,6 +395,30 @@ function get_endpoint_url(network_name) {
322
395
  if(process.env.GOERLI_RPC_URL && network_name === "goerli") {
323
396
  return process.env.GOERLI_RPC_URL;
324
397
  }
398
+ if(process.env.SEPOLIA_RPC_URL && network_name === "sepolia") {
399
+ return process.env.SEPOLIA_RPC_URL;
400
+ }
401
+ if(process.env.POLYGON_RPC_URL && network_name === "polygon") {
402
+ return process.env.POLYGON_RPC_URL;
403
+ }
404
+ if(process.env.MUMBAI_RPC_URL && network_name === "mumbai") {
405
+ return process.env.MUMBAI_RPC_URL;
406
+ }
407
+ if(process.env.BSC_RPC_URL && network_name === "binance") {
408
+ return process.env.BSC_RPC_URL;
409
+ }
410
+ if(process.env.BSC_TESTNET_RPC_URL && network_name === "binance_testnet") {
411
+ return process.env.BSC_TESTNET_RPC_URL;
412
+ }
413
+ if(process.env.BASE_RPC_URL && network_name === "base_mainnet") {
414
+ return process.env.BASE_RPC_URL;
415
+ }
416
+ if(process.env.BASE_GOERLI_RPC_URL && network_name === "base_goerli") {
417
+ return process.env.BASE_GOERLI_RPC_URL;
418
+ }
419
+ if(process.env.BASE_SEPOLIA_RPC_URL && network_name === "base_sepolia") {
420
+ return process.env.BASE_SEPOLIA_RPC_URL;
421
+ }
325
422
 
326
423
  // try the alchemy next
327
424
  // create a key: https://www.alchemy.com/
@@ -332,18 +429,45 @@ function get_endpoint_url(network_name) {
332
429
  case "rinkeby": return "https://eth-rinkeby.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
333
430
  case "kovan": return "https://eth-kovan.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
334
431
  case "goerli": return "https://eth-goerli.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
432
+ case "sepolia": return "https://eth-sepolia.alchemyapi.io/v2/" + process.env.ALCHEMY_KEY;
433
+ case "polygon": return "https://polygon-mainnet.g.alchemy.com/v2/" + process.env.ALCHEMY_KEY;
434
+ case "mumbai": return "https://polygon-mumbai.g.alchemy.com/v2/" + process.env.ALCHEMY_KEY;
435
+ case "base_mainnet": return "https://base-mainnet.g.alchemy.com/v2/" + process.env.ALCHEMY_KEY;
436
+ case "base_goerli": return "https://base-goerli.g.alchemy.com/v2/" + process.env.ALCHEMY_KEY;
437
+ case "base_sepolia": return "https://base-sepolia.g.alchemy.com/v2/" + process.env.ALCHEMY_KEY;
335
438
  }
336
439
  }
337
440
 
338
441
  // fallback to infura
339
442
  // create a key: https://infura.io/
443
+ if(process.env.INFURA_KEY) {
444
+ switch(network_name) {
445
+ case "mainnet": return "https://mainnet.infura.io/v3/" + process.env.INFURA_KEY;
446
+ case "ropsten": return "https://ropsten.infura.io/v3/" + process.env.INFURA_KEY;
447
+ case "rinkeby": return "https://rinkeby.infura.io/v3/" + process.env.INFURA_KEY;
448
+ case "kovan": return "https://kovan.infura.io/v3/" + process.env.INFURA_KEY;
449
+ case "goerli": return "https://goerli.infura.io/v3/" + process.env.INFURA_KEY;
450
+ case "sepolia": return "https://sepolia.infura.io/v3/" + process.env.INFURA_KEY;
451
+ case "polygon": return "https://polygon-mainnet.infura.io/v3/" + process.env.INFURA_KEY;
452
+ case "mumbai": return "https://polygon-mumbai.infura.io/v3/" + process.env.INFURA_KEY;
453
+ }
454
+ }
455
+
456
+ // some networks don't require API key
340
457
  switch(network_name) {
341
- case "mainnet": return "https://mainnet.infura.io/v3/" + process.env.INFURA_KEY;
342
- case "ropsten": return "https://ropsten.infura.io/v3/" + process.env.INFURA_KEY;
343
- case "rinkeby": return "https://rinkeby.infura.io/v3/" + process.env.INFURA_KEY;
344
- case "kovan": return "https://kovan.infura.io/v3/" + process.env.INFURA_KEY;
345
- case "goerli": return "https://goerli.infura.io/v3/" + process.env.INFURA_KEY;
458
+ case "polygon": return "https://polygon-rpc.com/";
459
+ case "mumbai": return "https://rpc-mumbai.maticvigil.com";
460
+ case "binance": return "https://bsc-dataseed1.binance.org/";
461
+ case "binance_testnet": return "https://data-seed-prebsc-1-s3.binance.org:8545/";
462
+ case "opBnb": return "https://opbnb-mainnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3";
463
+ case "opBnb_testnet": return "https://opbnb-testnet.nodereal.io/v1/9989d39cb7484ee9abcec2132a242315";
464
+ case "base_mainnet": return "https://mainnet.base.org";
465
+ case "base_goerli": return "https://goerli.base.org";
466
+ case "base_sepolia": return "https://sepolia.base.org";
346
467
  }
468
+
469
+ // fallback to default JSON_RPC_URL (if set)
470
+ return process.env.JSON_RPC_URL || "";
347
471
  }
348
472
 
349
473
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazy-sol/access-control",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
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,7 +22,7 @@
22
22
  "author": "Basil Gorin",
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
- "@lazy-sol/a-missing-gem": "^1.0.0",
25
+ "@lazy-sol/a-missing-gem": "^1.0.2",
26
26
  "@nomiclabs/hardhat-truffle5": "^2.0.7",
27
27
  "hardhat": "^2.16.0",
28
28
  "hardhat-deploy": "^0.11.45"
@@ -6,7 +6,7 @@ const {
6
6
  constants,
7
7
  expectEvent,
8
8
  expectRevert,
9
- } = require("@openzeppelin/test-helpers");
9
+ } = require("@lazy-sol/zeppelin-test-helpers");
10
10
  const {
11
11
  assert,
12
12
  expect,
@@ -4,7 +4,7 @@ const {
4
4
  constants,
5
5
  expectEvent,
6
6
  expectRevert,
7
- } = require("@openzeppelin/test-helpers");
7
+ } = require("@lazy-sol/zeppelin-test-helpers");
8
8
  const {
9
9
  assert,
10
10
  expect,
@@ -19,7 +19,7 @@ const {
19
19
  const {
20
20
  random_bn255,
21
21
  random_bn256,
22
- } = require("@lazy-sol/a-missing-jem/bn_utils");
22
+ } = require("@lazy-sol/a-missing-gem/bn_utils");
23
23
 
24
24
  // RBAC core features and roles
25
25
  const {
@@ -6,7 +6,7 @@ const {
6
6
  constants,
7
7
  expectEvent,
8
8
  expectRevert,
9
- } = require("@openzeppelin/test-helpers");
9
+ } = require("@lazy-sol/zeppelin-test-helpers");
10
10
  const {
11
11
  assert,
12
12
  expect,
@@ -6,7 +6,7 @@ const {
6
6
  constants,
7
7
  expectEvent,
8
8
  expectRevert,
9
- } = require("@openzeppelin/test-helpers");
9
+ } = require("@lazy-sol/zeppelin-test-helpers");
10
10
  const {
11
11
  assert,
12
12
  expect,
@@ -6,7 +6,7 @@ const {
6
6
  constants,
7
7
  expectEvent,
8
8
  expectRevert,
9
- } = require("@openzeppelin/test-helpers");
9
+ } = require("@lazy-sol/zeppelin-test-helpers");
10
10
  const {
11
11
  assert,
12
12
  expect,