@lazy-sol/access-control 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
1
+ {
2
+ "address": "0x7b581185b7912E45F882aE0B1512C32B8a96Dd3d",
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": "0x0632ff416ab98e2dd6af21d26f9e28c5b21d187557d8ec594d8734f3a7620a5f",
44
+ "receipt": {
45
+ "to": null,
46
+ "from": "0x5F185Da55f7BBD9217E3b3CeE06b180721FA6d34",
47
+ "contractAddress": "0x7b581185b7912E45F882aE0B1512C32B8a96Dd3d",
48
+ "transactionIndex": 24,
49
+ "gasUsed": "817257",
50
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
51
+ "blockHash": "0x446d6bacf0e956a26aa2d58f30bc71e24ef679c7ab54d33bd044b2cb938ae08b",
52
+ "transactionHash": "0x0632ff416ab98e2dd6af21d26f9e28c5b21d187557d8ec594d8734f3a7620a5f",
53
+ "logs": [],
54
+ "blockNumber": 9839388,
55
+ "cumulativeGasUsed": "8436686",
56
+ "status": 1,
57
+ "byzantium": true
58
+ },
59
+ "args": [],
60
+ "numDeployments": 1,
61
+ "solcInputHash": "9f8f20c7b4fd0796d45c56d37e790191",
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 private 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\\n\\t */\\n\\tconstructor(address _owner) 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}\\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) public 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\":\"0xf66d032e7c46ff4f5a61a7e963e8dea28ef667a0f6aa1d39b34c67e35e831198\",\"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\\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\":\"0xc5da22ffbabe0416a4c9407cace60b1f2c0b5851d15c5e936eb886534983a774\",\"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) {\\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\":\"0xbf6b8ccadb2ce5e687e82827ad60c5b8a1ea6ab9ca5afacb258c00faf4dd2875\",\"license\":\"MIT\"}},\"version\":1}",
63
+ "bytecode": "0x608060405234801561001057600080fd5b50610dd2806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80635020380814610030575b600080fd5b61004361003e3660046101c9565b61005f565b6040516001600160a01b03909116815260200160405180910390f35b6000336001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156100ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100cf91906101ed565b6001600160a01b0316146101185760405162461bcd60e51b815260206004820152600c60248201526b3737ba1030b71037bbb732b960a11b604482015260640160405180910390fd5b60008233604051610128906101a4565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801561015b573d6000803e3d6000fd5b509050826001600160a01b0316816001600160a01b03167f480c2ac1e89311d31b5f348c0934382be45d3bb75dfe35f2f209652fed1505b360405160405180910390a392915050565b610b928061020b83390190565b6001600160a01b03811681146101c657600080fd5b50565b6000602082840312156101db57600080fd5b81356101e6816101b1565b9392505050565b6000602082840312156101ff57600080fd5b81516101e6816101b156fe608060405234801561001057600080fd5b50604051610b92380380610b9283398101604081905261002f91610121565b8061003d81600019806100ad565b506001600160a01b0382166100875760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b604482015260640160405180910390fd5b50600180546001600160a01b0319166001600160a01b0392909216919091179055610154565b6001600160a01b0383166000818152602081815260409182902084905581518581529081018490527fe9be537308880e0f56b7d7cfd7abf85f14c4934486d138f848b92a0cbaf659b4910160405180910390a2505050565b80516001600160a01b038116811461011c57600080fd5b919050565b6000806040838503121561013457600080fd5b61013d83610105565b915061014b60208401610105565b90509250929050565b610a2f806101636000396000f3fe6080604052600436106100ec5760003560e01c8063725f36261161008a578063d4b8399211610059578063d4b83992146102e7578063d5bb7f671461031f578063f822d5aa1461033f578063fcc2c0781461035f5761010b565b8063725f36261461025f578063ae5b102e1461028f578063ae682e2e146102af578063c688d693146102c75761010b565b806334e48c9e116100c657806334e48c9e146101d157806344276733146101e9578063491d26111461021f5780635defb40d1461023f5761010b565b806309c5eabe1461014b5780630e82fe25146101745780632b521416146101af5761010b565b3661010b576101096040518060200160405280600081525061037f565b005b6101096000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061037f92505050565b61015e61015936600461076f565b61037f565b60405161016b9190610810565b60405180910390f35b34801561018057600080fd5b506101a161018f366004610840565b60026020526000908152604090205481565b60405190815260200161016b565b3480156101bb57600080fd5b50306000908152602081905260409020546101a1565b3480156101dd57600080fd5b506101a1600160fd1b81565b3480156101f557600080fd5b506101a1610204366004610872565b6001600160a01b031660009081526020819052604090205490565b34801561022b57600080fd5b5061010961023a36600461088d565b610509565b34801561024b57600080fd5b5061010961025a3660046108b7565b61058b565b34801561026b57600080fd5b5061027f61027a366004610910565b6105a0565b604051901515815260200161016b565b34801561029b57600080fd5b506101096102aa366004610929565b6105c2565b3480156102bb57600080fd5b506101a1600160ff1b81565b3480156102d357600080fd5b5061027f6102e2366004610929565b61061e565b3480156102f357600080fd5b50600154610307906001600160a01b031681565b6040516001600160a01b03909116815260200161016b565b34801561032b57600080fd5b5061010961033a366004610910565b610647565b34801561034b57600080fd5b506101a161035a366004610945565b610654565b34801561036b57600080fd5b5061027f61037a366004610910565b61067f565b60208101518151606091901561041b576001600160e01b03198116600090815260026020526040812054908190036103f45760405162461bcd60e51b81526020600482015260136024820152721858d8d95cdcc81c9bdb19481b9bdd081cd95d606a1b60448201526064015b60405180910390fd5b6103fd8161067f565b6104195760405162461bcd60e51b81526004016103eb90610978565b505b60015460405160009182916001600160a01b0390911690349061043f90889061099f565b60006040518083038185875af1925050503d806000811461047c576040519150601f19603f3d011682016040523d82523d6000602084013e610481565b606091505b5091509150816104c65760405162461bcd60e51b815260206004820152601060248201526f195e1958dd5d1a5bdb8819985a5b195960821b60448201526064016103eb565b7f57a62eca76fc623c92f161d2a4b851851ece707135ce2af1eec256d660571b6d8386836040516104f9939291906109bb565b60405180910390a1949350505050565b610516600160fd1b61067f565b6105325760405162461bcd60e51b81526004016103eb90610978565b6001600160e01b03198216600081815260026020908152604091829020849055815192835282018390527fdb8ed917742b49e83acd1322bcaa8f18b1e5f78a70784c43ea14db7ab50e628d910160405180910390a15050565b61059c828051906020012082610509565b5050565b306000908152602081905260408120546105bc905b8316831490565b92915050565b6105cf600160ff1b61067f565b6105eb5760405162461bcd60e51b81526004016103eb90610978565b61059c828261061933610613876001600160a01b031660009081526020819052604090205490565b86610654565b61068b565b6001600160a01b038216600090815260208190526040812054610640906105b5565b9392505050565b61065130826105c2565b50565b6001600160a01b03929092166000908152602081905260409020546000198084188216189216171690565b60006105bc338361061e565b6001600160a01b0383166000818152602081815260409182902084905581518581529081018490527fe9be537308880e0f56b7d7cfd7abf85f14c4934486d138f848b92a0cbaf659b4910160405180910390a2505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115610714576107146106e3565b604051601f8501601f19908116603f0116810190828211818310171561073c5761073c6106e3565b8160405280935085815286868601111561075557600080fd5b858560208301376000602087830101525050509392505050565b60006020828403121561078157600080fd5b813567ffffffffffffffff81111561079857600080fd5b8201601f810184136107a957600080fd5b6107b8848235602084016106f9565b949350505050565b60005b838110156107db5781810151838201526020016107c3565b50506000910152565b600081518084526107fc8160208601602086016107c0565b601f01601f19169290920160200192915050565b60208152600061064060208301846107e4565b80356001600160e01b03198116811461083b57600080fd5b919050565b60006020828403121561085257600080fd5b61064082610823565b80356001600160a01b038116811461083b57600080fd5b60006020828403121561088457600080fd5b6106408261085b565b600080604083850312156108a057600080fd5b6108a983610823565b946020939093013593505050565b600080604083850312156108ca57600080fd5b823567ffffffffffffffff8111156108e157600080fd5b8301601f810185136108f257600080fd5b610901858235602084016106f9565b95602094909401359450505050565b60006020828403121561092257600080fd5b5035919050565b6000806040838503121561093c57600080fd5b6108a98361085b565b60008060006060848603121561095a57600080fd5b6109638461085b565b95602085013595506040909401359392505050565b6020808252600d908201526c1858d8d95cdcc819195b9a5959609a1b604082015260600190565b600082516109b18184602087016107c0565b9190910192915050565b63ffffffff60e01b841681526060602082015260006109dd60608301856107e4565b82810360408401526109ef81856107e4565b969550505050505056fea2646970667358221220299ccaa4a1349ebdda3d33b786bcdfc785617f69bfe78156209634c81486f30f64736f6c63430008150033a2646970667358221220dfafe7db0eec338f1238afc48c957b42ed075e71ad1fe22330cb21864d2b74e564736f6c63430008150033",
64
+ "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80635020380814610030575b600080fd5b61004361003e3660046101c9565b61005f565b6040516001600160a01b03909116815260200160405180910390f35b6000336001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156100ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100cf91906101ed565b6001600160a01b0316146101185760405162461bcd60e51b815260206004820152600c60248201526b3737ba1030b71037bbb732b960a11b604482015260640160405180910390fd5b60008233604051610128906101a4565b6001600160a01b03928316815291166020820152604001604051809103906000f08015801561015b573d6000803e3d6000fd5b509050826001600160a01b0316816001600160a01b03167f480c2ac1e89311d31b5f348c0934382be45d3bb75dfe35f2f209652fed1505b360405160405180910390a392915050565b610b928061020b83390190565b6001600160a01b03811681146101c657600080fd5b50565b6000602082840312156101db57600080fd5b81356101e6816101b1565b9392505050565b6000602082840312156101ff57600080fd5b81516101e6816101b156fe608060405234801561001057600080fd5b50604051610b92380380610b9283398101604081905261002f91610121565b8061003d81600019806100ad565b506001600160a01b0382166100875760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b604482015260640160405180910390fd5b50600180546001600160a01b0319166001600160a01b0392909216919091179055610154565b6001600160a01b0383166000818152602081815260409182902084905581518581529081018490527fe9be537308880e0f56b7d7cfd7abf85f14c4934486d138f848b92a0cbaf659b4910160405180910390a2505050565b80516001600160a01b038116811461011c57600080fd5b919050565b6000806040838503121561013457600080fd5b61013d83610105565b915061014b60208401610105565b90509250929050565b610a2f806101636000396000f3fe6080604052600436106100ec5760003560e01c8063725f36261161008a578063d4b8399211610059578063d4b83992146102e7578063d5bb7f671461031f578063f822d5aa1461033f578063fcc2c0781461035f5761010b565b8063725f36261461025f578063ae5b102e1461028f578063ae682e2e146102af578063c688d693146102c75761010b565b806334e48c9e116100c657806334e48c9e146101d157806344276733146101e9578063491d26111461021f5780635defb40d1461023f5761010b565b806309c5eabe1461014b5780630e82fe25146101745780632b521416146101af5761010b565b3661010b576101096040518060200160405280600081525061037f565b005b6101096000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061037f92505050565b61015e61015936600461076f565b61037f565b60405161016b9190610810565b60405180910390f35b34801561018057600080fd5b506101a161018f366004610840565b60026020526000908152604090205481565b60405190815260200161016b565b3480156101bb57600080fd5b50306000908152602081905260409020546101a1565b3480156101dd57600080fd5b506101a1600160fd1b81565b3480156101f557600080fd5b506101a1610204366004610872565b6001600160a01b031660009081526020819052604090205490565b34801561022b57600080fd5b5061010961023a36600461088d565b610509565b34801561024b57600080fd5b5061010961025a3660046108b7565b61058b565b34801561026b57600080fd5b5061027f61027a366004610910565b6105a0565b604051901515815260200161016b565b34801561029b57600080fd5b506101096102aa366004610929565b6105c2565b3480156102bb57600080fd5b506101a1600160ff1b81565b3480156102d357600080fd5b5061027f6102e2366004610929565b61061e565b3480156102f357600080fd5b50600154610307906001600160a01b031681565b6040516001600160a01b03909116815260200161016b565b34801561032b57600080fd5b5061010961033a366004610910565b610647565b34801561034b57600080fd5b506101a161035a366004610945565b610654565b34801561036b57600080fd5b5061027f61037a366004610910565b61067f565b60208101518151606091901561041b576001600160e01b03198116600090815260026020526040812054908190036103f45760405162461bcd60e51b81526020600482015260136024820152721858d8d95cdcc81c9bdb19481b9bdd081cd95d606a1b60448201526064015b60405180910390fd5b6103fd8161067f565b6104195760405162461bcd60e51b81526004016103eb90610978565b505b60015460405160009182916001600160a01b0390911690349061043f90889061099f565b60006040518083038185875af1925050503d806000811461047c576040519150601f19603f3d011682016040523d82523d6000602084013e610481565b606091505b5091509150816104c65760405162461bcd60e51b815260206004820152601060248201526f195e1958dd5d1a5bdb8819985a5b195960821b60448201526064016103eb565b7f57a62eca76fc623c92f161d2a4b851851ece707135ce2af1eec256d660571b6d8386836040516104f9939291906109bb565b60405180910390a1949350505050565b610516600160fd1b61067f565b6105325760405162461bcd60e51b81526004016103eb90610978565b6001600160e01b03198216600081815260026020908152604091829020849055815192835282018390527fdb8ed917742b49e83acd1322bcaa8f18b1e5f78a70784c43ea14db7ab50e628d910160405180910390a15050565b61059c828051906020012082610509565b5050565b306000908152602081905260408120546105bc905b8316831490565b92915050565b6105cf600160ff1b61067f565b6105eb5760405162461bcd60e51b81526004016103eb90610978565b61059c828261061933610613876001600160a01b031660009081526020819052604090205490565b86610654565b61068b565b6001600160a01b038216600090815260208190526040812054610640906105b5565b9392505050565b61065130826105c2565b50565b6001600160a01b03929092166000908152602081905260409020546000198084188216189216171690565b60006105bc338361061e565b6001600160a01b0383166000818152602081815260409182902084905581518581529081018490527fe9be537308880e0f56b7d7cfd7abf85f14c4934486d138f848b92a0cbaf659b4910160405180910390a2505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115610714576107146106e3565b604051601f8501601f19908116603f0116810190828211818310171561073c5761073c6106e3565b8160405280935085815286868601111561075557600080fd5b858560208301376000602087830101525050509392505050565b60006020828403121561078157600080fd5b813567ffffffffffffffff81111561079857600080fd5b8201601f810184136107a957600080fd5b6107b8848235602084016106f9565b949350505050565b60005b838110156107db5781810151838201526020016107c3565b50506000910152565b600081518084526107fc8160208601602086016107c0565b601f01601f19169290920160200192915050565b60208152600061064060208301846107e4565b80356001600160e01b03198116811461083b57600080fd5b919050565b60006020828403121561085257600080fd5b61064082610823565b80356001600160a01b038116811461083b57600080fd5b60006020828403121561088457600080fd5b6106408261085b565b600080604083850312156108a057600080fd5b6108a983610823565b946020939093013593505050565b600080604083850312156108ca57600080fd5b823567ffffffffffffffff8111156108e157600080fd5b8301601f810185136108f257600080fd5b610901858235602084016106f9565b95602094909401359450505050565b60006020828403121561092257600080fd5b5035919050565b6000806040838503121561093c57600080fd5b6108a98361085b565b60008060006060848603121561095a57600080fd5b6109638461085b565b95602085013595506040909401359392505050565b6020808252600d908201526c1858d8d95cdcc819195b9a5959609a1b604082015260600190565b600082516109b18184602087016107c0565b9190910192915050565b63ffffffff60e01b841681526060602082015260006109dd60608301856107e4565b82810360408401526109ef81856107e4565b969550505050505056fea2646970667358221220299ccaa4a1349ebdda3d33b786bcdfc785617f69bfe78156209634c81486f30f64736f6c63430008150033a2646970667358221220dfafe7db0eec338f1238afc48c957b42ed075e71ad1fe22330cb21864d2b74e564736f6c63430008150033",
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,42 @@
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 private 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\n\t */\n\tconstructor(address _owner) 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}\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) public 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\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/OwnableToAccessControlAdapter.sol": {
11
+ "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) {\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"
12
+ }
13
+ },
14
+ "settings": {
15
+ "optimizer": {
16
+ "enabled": true,
17
+ "runs": 200
18
+ },
19
+ "evmVersion": "paris",
20
+ "outputSelection": {
21
+ "*": {
22
+ "*": [
23
+ "abi",
24
+ "evm.bytecode",
25
+ "evm.deployedBytecode",
26
+ "evm.methodIdentifiers",
27
+ "metadata",
28
+ "devdoc",
29
+ "userdoc",
30
+ "storageLayout",
31
+ "evm.gasEstimates"
32
+ ],
33
+ "": [
34
+ "ast"
35
+ ]
36
+ }
37
+ },
38
+ "metadata": {
39
+ "useLiteralContent": true
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,201 @@
1
+ # Where and How to Commit Your Work
2
+
3
+ ## Branches
4
+
5
+ - The code in the `develop` and `master` branches should always compile and pass all tests
6
+ - Issue branches. Naming scheme: `<username>/<issue-id>_<brief_description>`
7
+ - Username should be GitHub user name;
8
+ if you are well-known under a different nickname, using that nickname is acceptable
9
+ - Use GitHub issue id with dash in `issue-id`
10
+ - Use lowercase letters and underscores in `brief_description`
11
+ - Make sure the description is really brief but clear enough so that it is easy to understand what the issue is
12
+ about without looking it up in the issue tracker (assuming you are familiar with existing issues)
13
+ - Example:
14
+ - `vgorin/2_contribution_guide`
15
+
16
+ ## Commit Messages
17
+
18
+ - Follow [this guide](https://chris.beams.io/posts/git-commit/).
19
+ - First line should not end with a dot and should not exceed 100 characters in length
20
+ - Prefix the subject line with the ID of the relevant issue
21
+ - There should be an empty line between the caption and body if body present
22
+ - There may be (sequentially single) an empty line in the body
23
+ - First line, and each line after newline should be Capitalized
24
+ - Commit message body should contain a paragraph stating the problem ("Problem: ...") solved,
25
+ and then the description of the proposed solution ("Solution: ...").
26
+ - Message body may contain lists prefixed with ' - ' or ' * '
27
+ - Example is provided below:
28
+
29
+ ```
30
+ #2: Write the Contribution Guide
31
+
32
+ Problem: there is no contribution guide present in the template
33
+
34
+ Solution: adopt and add the contribution guide from the publicly available sources
35
+
36
+ ```
37
+
38
+ ## Commit History
39
+
40
+ Ideal commit history should satisfy the following criteria:
41
+
42
+ - Each commit should be a minimal and accurate answer to exactly one identified and agreed problem
43
+ - Each commit should not fix a problem introduced by an earlier commit in your pull request (PR)
44
+ or revert an earlier commit in the PR
45
+ - Your pull request generally shouldn't contain changes unrelated to the issue it solves;
46
+ if you modify some file and see an obvious small mistake there (a typo or wrong formatting),
47
+ you can fix it in your PR and add a description to the commit message
48
+
49
+ During the pull request review process, your commit history doesn't have to satisfy these criteria
50
+ What happened in PR stays in PR, but after PR is completed and merged, commit history must follow the criteria above.
51
+ All fixup commits should be merged into their origins.
52
+
53
+ See the Git hints section in the end of this doc if you have troubles making your history pretty.
54
+
55
+ All commits should be signed.
56
+ For more details please see [Signing commits](https://help.github.com/articles/signing-commits/).
57
+
58
+ All the commits should be done with your real email.
59
+
60
+ ## Pull Request - Issue Relation
61
+
62
+ Each pull request should resolve exactly one issue and each issue should be resolved by exactly one PR.
63
+ Don't start working on more than one issue at once. There are legitimate cases when it doesn't hold though:
64
+
65
+ 1. If someone (say Alice) needs to work on the issue which depends on or overlaps with your ongoing work,
66
+ you can create a PR for your work before you fully finish it and this PR can be merged as long as it doesn't break
67
+ anything. In this case Alice won't have to start her work from your issue branch.
68
+ However, if you are not confident your intermediate changes are stable (won't have to be redone)
69
+ it's better to have Alice start her work from your issue branch to avoid mess in the target branch,
70
+ creating a PR to your branch instead of the `develop` or `master`.
71
+ 2. Sometimes you may resolve issue A, while you are working on issue B,
72
+ simply because your solution for B also resolves A.
73
+ A doesn't duplicate B and solution for them wasn't known in advance, it just happened so.
74
+ In this case your PR can refer to more than one issue.
75
+ It's a rare case though, usually it's clear whether resolving B will also resolve A,
76
+ so if it's the case then A can be closed in advance.
77
+
78
+ Both cases are rare, so generally there should be 1-to-1 correspondence between issues and pull requests.
79
+
80
+ ### Pull Request Size
81
+
82
+ Try to avoid big PRs. The bigger your PR is, the harder it is to review it.
83
+ Some mistakes can be unnoticed, some minor concerns may be unreported simply because reviewer already reported
84
+ too many of them and got tired.
85
+ It's mentally hard to start reviewing a PR when you see that it's very big.
86
+ If your PR is big, but contains many commits which are small, it's still not perfect:
87
+ When reviewing on per-commit basis, if several commits require changes, tracking these changes becomes hard.
88
+
89
+ If you notice that your PR is quite big, please think whether the issue you are solving can be split into smaller ones.
90
+ If so please create smaller issues as sub tasks for your issue and create smaller PRs for each one.
91
+
92
+ There is no universal limit on PR size, sometimes even very large one is fine if it can't be split into smaller PRs
93
+ or if such split doesn't make sense.
94
+ If your PR has more than 500 additions + deletions, please think twice whether it can be split into smaller PRs.
95
+
96
+ ## Opening a Pull Request
97
+
98
+ 1. PR title should adhere to the following scheme: `[ISSUE-ID]: Brief Description`.
99
+ 2. PR description cannot be empty. If there is a PR template, the description should adhere to the template.
100
+ If there is no template, please describe the changes you've made and **why** you've made them.
101
+ Provide links to related issues.
102
+ 3. Request a review from one person you think would be the most suitable as a reviewer
103
+ (e.g. because you think they might be interested in your change or because they touched this code previously).
104
+ - If you *really* want to, request a review from one other person.
105
+ - If your changes are very simple, requesting a review from only **one person** is acceptable.
106
+ - Keep in mind that review might be automatically requested from code owners when you actually create a PR.
107
+ Make sure to review list of reviewers after pressing the `Create pull request` button.
108
+ 4. If PR is about work in progress (WIP), `WIP: ` prefix shall be added to the PR title.
109
+
110
+ ## Working on the Issue
111
+
112
+ 1. Before you start working on the new issue, make sure you have made all requested changes in all your open PRs.
113
+ 2. Starting from HEAD of the `develop` (`master`) branch, create a new *issue branch*. Please note:
114
+ - Some issues may require starting from a specific branch instead of `develop`.
115
+ - If the description of an issue doesn't specify target branch, and you suspect it may differ from `develop`,
116
+ clarify this in the issue's comments.
117
+ - Sometimes you may work on an issue which depends on the PR which is not yet merged.
118
+ In this case you need to start your branch from another issue branch.
119
+ Make sure first the code in that MR is sufficiently stable so that you won't have to redo much work.
120
+ 3. Make your changes.
121
+ 4. Open a pull request.
122
+ 5. Wait for reviews to arrive.
123
+ If people whose review was requested do not review your PR, explicitly ask them to review it.
124
+ In case when they don't react for too long (let's say one working day),
125
+ contact the repository maintainer, or a team lead
126
+ (if there is a dedicated team working on the contents of the repository).
127
+ If you are not a core team member and don't know whom to ask,
128
+ write about it to the most active contributors of the repository.
129
+ 6. Make sure to synchronize your issue branch with the target branch of your PR sometimes to avoid excessive conflicts.
130
+ How often you should do it depends on speed of development in the target branch.
131
+ You should do it by rebasing your branch on the target branch.
132
+ It's acceptable to merge target branch into your branch only if rebase takes significantly more time
133
+ (which should be the case only for big PRs with long commit history).
134
+ In this case, please perform interactive rebase and prettify your history prior to merging,
135
+ because doing so after merge can be much harder.
136
+ 7. If there are comments on your PR that need to be addressed, make the changes, push them and notify people who
137
+ requested the changes.
138
+ 8. Make requested changes in separate commits, don't amend previous commits and don't force push.
139
+ At this point your commit history may fail the criteria listed above which is fine.
140
+ Clean-up commit history after all reviewers approve your PR (by force-pushing).
141
+ Force-push is permitted only if you push the same commits rebased on a newer version of the target branch.
142
+ - The exception is the case from item (6) when you merge target branch into your branch.
143
+ These cases should be rare.
144
+ In such cases please use your best judgement to avoid complicating review of the changes requested by reviewers.
145
+ 9. By default, you can assume that nobody except you will work in your branch, so you can feel free to force-push.
146
+ However, if you know there is someone else working in your branch, don't force-push without getting an approval
147
+ from your colleague. **Always** use the `--force-with-lease` option when you force-push.
148
+
149
+ ## Merging a Pull Request
150
+
151
+ If all the reviewers approved the pull request and all mandatory checks have passed,
152
+ it's time to merge the pull request.
153
+ Before merging, please check whether commit history satisfies the criteria listed above,
154
+ because approval generally implies that reviewer is satisfied with code changes,
155
+ but doesn't necessarily imply a good commit history.
156
+ If commit history needs to be modified, the PR author has to do it.
157
+
158
+ A PR can be merged by its author or by one of the reviewers.
159
+
160
+ 1. It's usually better to let the PR author to merge their PR to give them a chance to polish commit history
161
+ before merging.
162
+ 2. Since it may take some time for the PR author to merge their PR and since the sooner a good PR is merged, the better,
163
+ the reviewer can merge the PR instead.
164
+ The reviewer needs to make sure the PR author doesn't wish to do anything with the commit history.
165
+ For example, if a PR is a trivial one-liner, this should be obvious. Do not merge if you are not sure.
166
+
167
+ GitHub offers three options to merge a PR:
168
+
169
+ 1. Create a merge commit.
170
+ 2. Squash and merge.
171
+ 3. Rebase and merge.
172
+
173
+ Always use the first option to preserve PR's commit history.
174
+
175
+ Note that all fixup commits shall be squashed into origins before the merge.
176
+
177
+ ## Git Hints
178
+
179
+ - Here you may find some useful git commands and command line options to comply with our workflow.
180
+ This information is mostly for beginners, experienced git users should be familiar with most of it.
181
+ It's not a descriptive guide, just a list of things you should be aware of.
182
+ Detailed descriptions can be found in man pages.
183
+ - To synchronize your issue branch with the target branch by means of rebase,
184
+ checkout to your branch, do `git fetch` and then `git rebase origin/<target>`
185
+ where `<target>` is usually `develop`. You may have to resolve conflicts.
186
+ - The above works only if there were no force-pushes in the target branch.
187
+ If your target branch is an issue branch, there can be force-pushes.
188
+ This branch can be merged to its target branch and then you'll need to rebase on another target branch.
189
+ In such case pass `--onto <newbase>` flag to `git rebase`.
190
+ `<newbase>` should be a commit on top of which your commits will be reapplied.
191
+ Normally it is HEAD of your target branch.
192
+ - If you have dirty commit history in your branch and want to make it look better,
193
+ interactive rebase is your best friend.
194
+ Pass `-i` flag to the `git rebase` command.
195
+ It allows you to squash commits, reorder them, split into smaller commits, amend old commits, etc.
196
+ - If you want to add only a subset of changes of a file, you can pass `-p` flag to the `git add` command.
197
+ - If you are making changes requested on your pull request, and these changes fix something introduced by
198
+ your previous commit in the same PR, use `--fixup` option of `git commit`.
199
+ - If you need to force push, always use `--force-with-lease` flag instead of `-f`.
200
+ This option is safer, because it checks that remote branch is in the state you expect.
201
+ Consider creating a shell alias if you find it tedious to type this flag.
@@ -0,0 +1,40 @@
1
+ <!--
2
+ Specify the issued ID and title (ex.: #2: Write the Contribution Guide)
3
+ Describe the problem in your own words or as it is described in GitHub issue
4
+ Describe the proposed solution
5
+ -->
6
+
7
+ GitHub-issue-ID: GitHub Issue Title
8
+
9
+ Problem:
10
+
11
+ Solution:
12
+
13
+ # Checklist for a Pull Request
14
+
15
+ <!--
16
+ Ideally a PR has all the checkmarks set.
17
+
18
+ If something in this list is irrelevant to your PR, you should still set this
19
+ checkmark indicating that you are sure it is dealt with (be that by irrelevance).
20
+
21
+ If you don't set a checkmark (e.g. don't add a test for new functionality),
22
+ you must be able to justify that.
23
+ -->
24
+
25
+ ## Related Changes (Conditional)
26
+
27
+ - Tests
28
+ - [ ] I've added tests covering new functionality or there is a follow-up issue to create the tests
29
+ - [ ] I've added a regression test to prevent the bug I've fixed from silently reappearing again
30
+
31
+ - Documentation
32
+ - I've checked whether I should update the docs and did so if necessary:
33
+ - [ ] [README](../README.md)
34
+ - [ ] SolDoc
35
+
36
+ ## Style Guide (Mandatory)
37
+
38
+ - [ ] My commits comply with [commit policy](./commit_policy.md).
39
+ - [ ] My code complies with the [style guides](./style_guides.md).
40
+ - [ ] Code of repository compiles and tests pass, i.e. `npx hardhat test` execute successfully.