@ensuro/access-managed-proxy 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +47 -4
  2. package/build/build-info.json +1 -1
  3. package/build/contracts/AMPUtils.sol/AMPUtils.json +22 -0
  4. package/build/contracts/AccessManagedProxy.sol/AccessManagedProxy.json +71 -3
  5. package/build/contracts/AccessManagedProxyBase.sol/AccessManagedProxyBase.json +147 -0
  6. package/build/contracts/interfaces/IAccessManagedProxy.sol/IAccessManagedProxy.json +98 -0
  7. package/build/contracts/mock/DummyAccessManaged.sol/DummyAccessManaged.json +321 -0
  8. package/build/contracts/mock/DummyImplementation.sol/DummyImplementation.json +95 -2
  9. package/contracts/AMPUtils.sol +88 -0
  10. package/contracts/AccessManagedProxy.sol +39 -51
  11. package/contracts/AccessManagedProxyBase.sol +74 -0
  12. package/contracts/interfaces/IAccessManagedProxy.sol +51 -0
  13. package/contracts/mock/DummyAccessManaged.sol +56 -0
  14. package/contracts/mock/DummyImplementation.sol +19 -2
  15. package/js/deployProxy.js +69 -0
  16. package/package.json +1 -1
  17. package/build/contracts/amps/AccessManagedProxyS1.sol/AccessManagedProxyS1.json +0 -123
  18. package/build/contracts/amps/AccessManagedProxyS10.sol/AccessManagedProxyS10.json +0 -123
  19. package/build/contracts/amps/AccessManagedProxyS11.sol/AccessManagedProxyS11.json +0 -123
  20. package/build/contracts/amps/AccessManagedProxyS12.sol/AccessManagedProxyS12.json +0 -123
  21. package/build/contracts/amps/AccessManagedProxyS13.sol/AccessManagedProxyS13.json +0 -123
  22. package/build/contracts/amps/AccessManagedProxyS14.sol/AccessManagedProxyS14.json +0 -123
  23. package/build/contracts/amps/AccessManagedProxyS15.sol/AccessManagedProxyS15.json +0 -123
  24. package/build/contracts/amps/AccessManagedProxyS16.sol/AccessManagedProxyS16.json +0 -123
  25. package/build/contracts/amps/AccessManagedProxyS17.sol/AccessManagedProxyS17.json +0 -123
  26. package/build/contracts/amps/AccessManagedProxyS18.sol/AccessManagedProxyS18.json +0 -123
  27. package/build/contracts/amps/AccessManagedProxyS19.sol/AccessManagedProxyS19.json +0 -123
  28. package/build/contracts/amps/AccessManagedProxyS2.sol/AccessManagedProxyS2.json +0 -123
  29. package/build/contracts/amps/AccessManagedProxyS20.sol/AccessManagedProxyS20.json +0 -123
  30. package/build/contracts/amps/AccessManagedProxyS21.sol/AccessManagedProxyS21.json +0 -123
  31. package/build/contracts/amps/AccessManagedProxyS22.sol/AccessManagedProxyS22.json +0 -123
  32. package/build/contracts/amps/AccessManagedProxyS23.sol/AccessManagedProxyS23.json +0 -123
  33. package/build/contracts/amps/AccessManagedProxyS24.sol/AccessManagedProxyS24.json +0 -123
  34. package/build/contracts/amps/AccessManagedProxyS3.sol/AccessManagedProxyS3.json +0 -123
  35. package/build/contracts/amps/AccessManagedProxyS4.sol/AccessManagedProxyS4.json +0 -123
  36. package/build/contracts/amps/AccessManagedProxyS5.sol/AccessManagedProxyS5.json +0 -123
  37. package/build/contracts/amps/AccessManagedProxyS6.sol/AccessManagedProxyS6.json +0 -123
  38. package/build/contracts/amps/AccessManagedProxyS7.sol/AccessManagedProxyS7.json +0 -123
  39. package/build/contracts/amps/AccessManagedProxyS8.sol/AccessManagedProxyS8.json +0 -123
  40. package/build/contracts/amps/AccessManagedProxyS9.sol/AccessManagedProxyS9.json +0 -123
  41. package/contracts/amps/AccessManagedProxyS1.sol +0 -63
  42. package/contracts/amps/AccessManagedProxyS10.sol +0 -99
  43. package/contracts/amps/AccessManagedProxyS11.sol +0 -103
  44. package/contracts/amps/AccessManagedProxyS12.sol +0 -107
  45. package/contracts/amps/AccessManagedProxyS13.sol +0 -111
  46. package/contracts/amps/AccessManagedProxyS14.sol +0 -115
  47. package/contracts/amps/AccessManagedProxyS15.sol +0 -119
  48. package/contracts/amps/AccessManagedProxyS16.sol +0 -123
  49. package/contracts/amps/AccessManagedProxyS17.sol +0 -127
  50. package/contracts/amps/AccessManagedProxyS18.sol +0 -131
  51. package/contracts/amps/AccessManagedProxyS19.sol +0 -135
  52. package/contracts/amps/AccessManagedProxyS2.sol +0 -67
  53. package/contracts/amps/AccessManagedProxyS20.sol +0 -139
  54. package/contracts/amps/AccessManagedProxyS21.sol +0 -143
  55. package/contracts/amps/AccessManagedProxyS22.sol +0 -147
  56. package/contracts/amps/AccessManagedProxyS23.sol +0 -151
  57. package/contracts/amps/AccessManagedProxyS24.sol +0 -155
  58. package/contracts/amps/AccessManagedProxyS3.sol +0 -71
  59. package/contracts/amps/AccessManagedProxyS4.sol +0 -75
  60. package/contracts/amps/AccessManagedProxyS5.sol +0 -79
  61. package/contracts/amps/AccessManagedProxyS6.sol +0 -83
  62. package/contracts/amps/AccessManagedProxyS7.sol +0 -87
  63. package/contracts/amps/AccessManagedProxyS8.sol +0 -91
  64. package/contracts/amps/AccessManagedProxyS9.sol +0 -95
@@ -1,85 +1,73 @@
1
- // SPDX-License-Identifier: MIT
1
+ // SPDX-License-Identifier: Apache-2.0
2
2
  pragma solidity ^0.8.0;
3
3
 
4
- import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
5
4
  import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
5
+ import {IAccessManagedProxy} from "./interfaces/IAccessManagedProxy.sol";
6
+ import {AccessManagedProxyBase} from "./AccessManagedProxyBase.sol";
7
+ import {AMPUtils} from "./AMPUtils.sol";
6
8
 
7
9
  /**
8
10
  * @title AccessManagedProxy
9
- * @notice Proxy contract using IAccessManager to manage access control before delegating calls.
11
+ * @notice Proxy contract using IAccessManager to manage access control before delegating calls (mutable version)
10
12
  * @dev It's a variant of ERC1967Proxy.
11
13
  *
12
- * Currently the check is executed on any call received by the proxy contract even calls to view methods
13
- * (staticcall). In the setup of the ACCESS_MANAGER permissions you would want to make all the views and pure
14
- * functions enabled for the PUBLIC_ROLE.
14
+ * Currently the check is executed on any call received by the proxy contract (even calls to view methods, i.e.
15
+ * staticcall). For gas efficiency, you can also have `passThruMethods`, and for those methods it will skip
16
+ * the call to the AccessManager, calling directly to the implementation contract.
15
17
  *
16
- * For gas efficiency, the ACCESS_MANAGER is immutable, so take care you don't lose control of it, otherwise
17
- * it will make your contract inaccesible or other bad things will happen.
18
+ * The accessManager and the passThruMethods are in the storage, but this contract doesn't include any method
19
+ * to modify them. They should be modified by the implementation contract (check AMPUtils for functions that
20
+ * encapsulate these operations).
18
21
  *
19
22
  * Check https://forum.openzeppelin.com/t/accessmanagedproxy-is-a-good-idea/41917 for a discussion on the
20
- * advantages and disadvantages of using it.
23
+ * advantages and disadvantages of using it. Also https://www.youtube.com/watch?v=DKdwJ9Ap9vM for a presentation
24
+ * on this approach.
21
25
  *
22
26
  * @custom:security-contact security@ensuro.co
23
27
  * @author Ensuro
24
28
  */
25
- contract AccessManagedProxy is ERC1967Proxy {
26
- /**
27
- * @notice AccessManager contract that handles the permissions to access the implementation methods
28
- */
29
- IAccessManager public immutable ACCESS_MANAGER;
30
-
31
- // Error copied from IAccessManaged
32
- error AccessManagedUnauthorized(address caller);
29
+ contract AccessManagedProxy is AccessManagedProxyBase {
30
+ /// @custom:storage-location erc7201:ensuro.storage.AccessManagedProxy
31
+ /// For struct AMPUtils.AccessManagedProxyStorage
33
32
 
34
33
  /**
35
34
  * @notice Constructor of the proxy, defining the implementation and the access manager
36
35
  * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation` and
37
- * with `manager` as the ACCESS_MANAGER that will handle access control.
36
+ * with `accessManager` as the ACCESS_MANAGER that will handle access control.
38
37
  *
39
38
  * @param implementation The initial implementation contract.
40
39
  * @param _data If nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
41
40
  * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
42
- * @param manager The access manager that will handle access control
41
+ * @param accessManager The access manager that will handle access control
42
+ * @param passThruMethods The selector of methods that will skip the access control validation, typically used for
43
+ * views and other methods for gas optimization.
43
44
  *
44
- * Requirements:
45
- *
46
- * - If `data` is empty, `msg.value` must be zero.
45
+ * @custom:pre If `_data` is empty, `msg.value` must be zero.
47
46
  */
48
47
  constructor(
49
48
  address implementation,
50
49
  bytes memory _data,
51
- IAccessManager manager
52
- ) payable ERC1967Proxy(implementation, _data) {
53
- ACCESS_MANAGER = manager;
50
+ IAccessManager accessManager,
51
+ bytes4[] memory passThruMethods
52
+ ) payable AccessManagedProxyBase(implementation, _data) {
53
+ AMPUtils.setAccessManager(accessManager);
54
+ AMPUtils.setPassThruMethods(passThruMethods);
54
55
  }
55
56
 
56
- /**
57
- * @notice Intercepts the super._delegate call to implement access control
58
- * @dev Checks with the ACCESS_MANAGER if msg.sender is authorized to call the current call's function,
59
- * and if so, delegates the current call to `implementation`.
60
- * @param implementation The implementation contract
61
- *
62
- * This function does not return to its internal call site, it will return directly to the external caller.
63
- */
64
- function _delegate(address implementation) internal virtual override {
65
- bytes4 selector = bytes4(msg.data[0:4]);
66
- bool immediate = _skipAC(selector); // reuse immediate variable both for skipped methods and canCall result
67
- if (!immediate) {
68
- (immediate, ) = ACCESS_MANAGER.canCall(msg.sender, address(this), selector);
69
- if (!immediate) revert AccessManagedUnauthorized(msg.sender);
70
- }
71
- super._delegate(implementation);
57
+ /// @inheritdoc AccessManagedProxyBase
58
+ function _skipAC(bytes4 selector) internal view override returns (bool) {
59
+ return AMPUtils.getAccessManagedProxyStorage().skipAc[selector];
72
60
  }
73
61
 
74
- /**
75
- * @notice Returns whether to skip the access control validation or not
76
- * @dev Hook called before ACCESS_MANAGER.canCall to enable skipping the call to the access manager for performance
77
- * reasons (for example on views) or to remove access control for other specific cases
78
- * @param selector The selector of the method called
79
- * @return Whether the access control using ACCESS_MANAGER should be skipped or not
80
- */
81
- // solhint-disable-next-line no-unused-vars
82
- function _skipAC(bytes4 selector) internal view virtual returns (bool) {
83
- return false;
62
+ /// @inheritdoc IAccessManagedProxy
63
+ // solhint-disable-next-line func-name-mixedcase
64
+ function PASS_THRU_METHODS() external view override returns (bytes4[] memory methods) {
65
+ return AMPUtils.getAccessManagedProxyStorage().passThruMethods;
66
+ }
67
+
68
+ /// @inheritdoc IAccessManagedProxy
69
+ // solhint-disable-next-line func-name-mixedcase
70
+ function ACCESS_MANAGER() public view override returns (IAccessManager) {
71
+ return AMPUtils.getAccessManagedProxyStorage().accessManager;
84
72
  }
85
73
  }
@@ -0,0 +1,74 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
5
+ import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
6
+ import {IAccessManagedProxy} from "./interfaces/IAccessManagedProxy.sol";
7
+
8
+ /**
9
+ * @title AccessManagedProxyBase
10
+ * @notice Proxy contract using IAccessManager to manage access control before delegating calls.
11
+ * @dev It's a variant of ERC1967Proxy.
12
+ *
13
+ * Currently the check is executed on any call received by the proxy contract even calls to view methods
14
+ * (staticcall). In the setup of the ACCESS_MANAGER permissions you would want to make all the views and pure
15
+ * functions enabled for the PUBLIC_ROLE.
16
+ *
17
+ * This base contract delegates on descendent contracts the storage of the ACCESS_MANAGER.
18
+ *
19
+ * Check https://forum.openzeppelin.com/t/accessmanagedproxy-is-a-good-idea/41917 for a discussion on the
20
+ * advantages and disadvantages of using it.
21
+ *
22
+ * @custom:security-contact security@ensuro.co
23
+ * @author Ensuro
24
+ */
25
+ abstract contract AccessManagedProxyBase is ERC1967Proxy, IAccessManagedProxy {
26
+ /**
27
+ * @notice Constructor of the proxy, defining the implementation and the access manager
28
+ * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation` and
29
+ * with `manager` as the ACCESS_MANAGER that will handle access control.
30
+ *
31
+ * @param implementation The initial implementation contract.
32
+ * @param _data If nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
33
+ * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
34
+ *
35
+ * @custom:pre If `_data` is empty, `msg.value` must be zero.
36
+ */
37
+ constructor(address implementation, bytes memory _data) payable ERC1967Proxy(implementation, _data) {}
38
+
39
+ /// @inheritdoc IAccessManagedProxy
40
+ // solhint-disable-next-line func-name-mixedcase
41
+ function ACCESS_MANAGER() public view virtual returns (IAccessManager);
42
+
43
+ /// @inheritdoc IAccessManagedProxy
44
+ function authority() external view virtual returns (address) {
45
+ return address(ACCESS_MANAGER());
46
+ }
47
+
48
+ /**
49
+ * @notice Intercepts the super._delegate call to implement access control
50
+ * @dev Checks with the ACCESS_MANAGER if msg.sender is authorized to call the current call's function,
51
+ * and if so, delegates the current call to `implementation`.
52
+ * @param implementation The implementation contract
53
+ *
54
+ * This function does not return to its internal call site, it will return directly to the external caller.
55
+ */
56
+ function _delegate(address implementation) internal virtual override {
57
+ bytes4 selector = bytes4(msg.data[0:4]);
58
+ bool immediate = _skipAC(selector); // reuse immediate variable both for skipped methods and canCall result
59
+ if (!immediate) {
60
+ (immediate, ) = ACCESS_MANAGER().canCall(msg.sender, address(this), selector);
61
+ if (!immediate) revert AccessManagedUnauthorized(msg.sender);
62
+ }
63
+ super._delegate(implementation);
64
+ }
65
+
66
+ /**
67
+ * @notice Returns whether to skip the access control validation or not
68
+ * @dev Hook called before ACCESS_MANAGER.canCall to enable skipping the call to the access manager for performance
69
+ * reasons (for example on views) or to remove access control for other specific cases
70
+ * @param selector The selector of the method called
71
+ * @return Whether the access control using ACCESS_MANAGER should be skipped or not
72
+ */
73
+ function _skipAC(bytes4 selector) internal view virtual returns (bool);
74
+ }
@@ -0,0 +1,51 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
5
+
6
+ /**
7
+ * @title IAccessManagedProxy - Interface of AccessManagedProxy contracts
8
+ * @notice This interface gives observability of the access control setup
9
+ *
10
+ * @dev The `ACCESS_MANAGER()` is the AccessManager contract that stores the access roles for most of the methods,
11
+ * except those listed in `PASS_THRU_METHODS()` that are forwarded directly to the proxy and don't have access control
12
+ * (at least not by the AccessManager contract).
13
+ *
14
+ * @author Ensuro
15
+ */
16
+ interface IAccessManagedProxy {
17
+ /**
18
+ * @notice The ACCESS_MANAGER that manages the access controls was updated
19
+ * @dev Authority that manages this contract was updated. Uses same interface as OZ's IAccessManaged
20
+ */
21
+ // solhint-disable-next-line gas-indexed-events
22
+ event AuthorityUpdated(address authority);
23
+
24
+ /**
25
+ * @dev Emitted when the passThruMethods has changed.
26
+ */
27
+ event PassThruMethodsChanged(bytes4[] newPassThruMethods);
28
+
29
+ // Errors copied from OZ's IAccessManaged
30
+ error AccessManagedUnauthorized(address caller);
31
+ error AccessManagedInvalidAuthority(address authority);
32
+
33
+ /**
34
+ * @notice Returns the current authority.
35
+ * @dev Returns the current authority. Same as ACCESS_MANAGER(), added for compatibility with OZ's IAccessManaged
36
+ */
37
+ function authority() external view returns (address);
38
+
39
+ /**
40
+ * @notice AccessManager contract that handles the permissions to access the implementation methods
41
+ */
42
+ // solhint-disable-next-line func-name-mixedcase
43
+ function ACCESS_MANAGER() external view returns (IAccessManager);
44
+
45
+ /**
46
+ * @notice Gives observability to the methods that are skipped from access control
47
+ * @return methods The list of method selectors that skip ACCESS_MANAGER access control
48
+ */
49
+ // solhint-disable-next-line func-name-mixedcase
50
+ function PASS_THRU_METHODS() external view returns (bytes4[] memory methods);
51
+ }
@@ -0,0 +1,56 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.16;
3
+
4
+ import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
5
+ import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
6
+
7
+ /**
8
+ * @title Dummy implementation contract that supports upgrade and logs methods called
9
+ *
10
+ * @custom:security-contact security@ensuro.co
11
+ * @author Ensuro
12
+ */
13
+ contract DummyAccessManaged is AccessManagedUpgradeable, UUPSUpgradeable {
14
+ event MethodCalled(bytes4 selector);
15
+
16
+ /// @custom:oz-upgrades-unsafe-allow constructor
17
+ constructor() {
18
+ _disableInitializers();
19
+ }
20
+
21
+ function initialize(address initialAuthority) public virtual initializer {
22
+ __AccessManaged_init(initialAuthority);
23
+ }
24
+
25
+ /// @inheritdoc UUPSUpgradeable
26
+ function _authorizeUpgrade(address newImplementation) internal override {}
27
+
28
+ // For making gas usage comparisons easier, I'm going to use different methods for each variant
29
+ function callThruAMP() external restricted {
30
+ emit MethodCalled(this.callThruAMP.selector);
31
+ }
32
+
33
+ function callThru1967() external {
34
+ emit MethodCalled(this.callThru1967.selector);
35
+ }
36
+
37
+ function callDirect() external {
38
+ emit MethodCalled(this.callDirect.selector);
39
+ }
40
+
41
+ function callThruAMPSkippedMethod() external {
42
+ emit MethodCalled(this.callThruAMPSkippedMethod.selector);
43
+ }
44
+
45
+ function callThruAMPNonSkippedMethod() external restricted {
46
+ emit MethodCalled(this.callThruAMPNonSkippedMethod.selector);
47
+ }
48
+
49
+ function viewMethod() external view returns (address) {
50
+ return msg.sender;
51
+ }
52
+
53
+ function pureMethod() external pure returns (uint256) {
54
+ return 123456;
55
+ }
56
+ }
@@ -1,7 +1,10 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  pragma solidity ^0.8.16;
3
3
 
4
- import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
4
+ import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
5
+ import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
6
+ import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
7
+ import {AMPUtils} from "../AMPUtils.sol";
5
8
 
6
9
  /**
7
10
  * @title Dummy implementation contract that supports upgrade and logs methods called
@@ -9,7 +12,7 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U
9
12
  * @custom:security-contact security@ensuro.co
10
13
  * @author Ensuro
11
14
  */
12
- contract DummyImplementation is UUPSUpgradeable {
15
+ contract DummyImplementation is UUPSUpgradeable, Initializable {
13
16
  event MethodCalled(bytes4 selector);
14
17
 
15
18
  /// @custom:oz-upgrades-unsafe-allow constructor
@@ -50,4 +53,18 @@ contract DummyImplementation is UUPSUpgradeable {
50
53
  function pureMethod() external pure returns (uint256) {
51
54
  return 123456;
52
55
  }
56
+
57
+ function setAuthority(address newAuthority) external {
58
+ AMPUtils.setAccessManager(IAccessManager(newAuthority));
59
+ }
60
+
61
+ function setPassThruMethods(bytes4[] memory newPTMethods) external {
62
+ AMPUtils.replacePassThruMethods(newPTMethods);
63
+ }
64
+
65
+ function checkCanCall(bytes memory something) external returns (bytes4 selector) {
66
+ selector = AMPUtils.makeSelector(something);
67
+ AMPUtils.checkCanCall(msg.sender, selector);
68
+ emit MethodCalled(selector);
69
+ }
53
70
  }
@@ -0,0 +1,69 @@
1
+ const hre = require("hardhat");
2
+ const { ethers } = hre;
3
+ const { deploy: ozUpgradesDeploy } = require("@openzeppelin/hardhat-upgrades/dist/utils");
4
+
5
+ /**
6
+ * Deploys a contract using an AccessManagedProxy. Similar to hre.upgrades.deployProxy, but using AccessManagedProxy
7
+ *
8
+ * @param {contractFactory} The contract factory of the implementation contract
9
+ * @param {initializeArgs} Arguments for `initialize`
10
+ * @param {opts} Options for hre.upgrades.deployProxy with some AccessManagedProxy additions:
11
+ * - skipViewsAndPure: if true, deploys a proxy that will skip the access control for all the view and
12
+ * pure methods
13
+ * - skipMethods: list of method names that will skip the access control. Added to views and pure, if
14
+ * skipViewsAndPure is true.
15
+ * - acMgr: mandatory argument that will be used for the AMP
16
+ * @returns {contract} Promise<Contract>
17
+ */
18
+ async function deployAMPProxy(contractFactory, initializeArgs = [], opts = {}) {
19
+ const { acMgr, skipViewsAndPure, skipMethods } = opts;
20
+ if (acMgr === undefined) throw new Error("Missing required `acMgr` in opts");
21
+ let skipSelectors = [];
22
+ if (skipViewsAndPure) {
23
+ skipSelectors = contractFactory.interface.fragments
24
+ .filter(
25
+ (fragment) =>
26
+ fragment.type === "function" && (fragment.stateMutability === "pure" || fragment.stateMutability === "view")
27
+ )
28
+ .map((fragment) => fragment.selector);
29
+ }
30
+ if (skipMethods !== undefined && skipMethods.length > 0) {
31
+ skipSelectors.push(
32
+ ...skipMethods.map((method) =>
33
+ method.startsWith("0x") ? method : contractFactory.interface.getFunction(method).selector
34
+ )
35
+ );
36
+ }
37
+ let proxyFactory, deployFunction;
38
+ proxyFactory = await ethers.getContractFactory(opts.proxyClass || "AccessManagedProxy");
39
+ deployFunction = async (hre_, opts, factory, ...args) =>
40
+ ozUpgradesDeploy(hre_, opts, factory, ...args, acMgr, skipSelectors);
41
+
42
+ return hre.upgrades.deployProxy(contractFactory, initializeArgs, {
43
+ ...opts,
44
+ kind: "uups",
45
+ proxyFactory,
46
+ deployFunction,
47
+ });
48
+ }
49
+
50
+ async function attachAsAMP(contract, ampContractFactory = undefined) {
51
+ ampContractFactory = ampContractFactory || (await ethers.getContractFactory("AccessManagedProxy"));
52
+ return ampContractFactory.attach(contract);
53
+ }
54
+
55
+ async function getAccessManager(contract, ampContractFactory = undefined, accessManagerFactory = "AccessManager") {
56
+ const contractAsAMP = await attachAsAMP(contract, ampContractFactory);
57
+ return ethers.getContractAt(accessManagerFactory, await contractAsAMP.ACCESS_MANAGER());
58
+ }
59
+
60
+ function makeSelector(role) {
61
+ return ethers.keccak256(ethers.toUtf8Bytes(role)).slice(0, 10);
62
+ }
63
+
64
+ module.exports = {
65
+ deployAMPProxy,
66
+ attachAsAMP,
67
+ getAccessManager,
68
+ makeSelector,
69
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ensuro/access-managed-proxy",
3
3
  "description": "Variant of ERC-1967 proxy with built-in access control using OZ 5.x AccessManager",
4
- "version": "0.1.0",
4
+ "version": "0.3.0",
5
5
  "files": [
6
6
  "**/*.sol",
7
7
  "/build",
@@ -1,123 +0,0 @@
1
- {
2
- "_format": "hh-sol-artifact-1",
3
- "contractName": "AccessManagedProxyS1",
4
- "sourceName": "contracts/amps/AccessManagedProxyS1.sol",
5
- "abi": [
6
- {
7
- "inputs": [
8
- {
9
- "internalType": "address",
10
- "name": "implementation",
11
- "type": "address"
12
- },
13
- {
14
- "internalType": "bytes",
15
- "name": "_data",
16
- "type": "bytes"
17
- },
18
- {
19
- "internalType": "contract IAccessManager",
20
- "name": "manager",
21
- "type": "address"
22
- },
23
- {
24
- "internalType": "bytes4[1]",
25
- "name": "passThruMethods",
26
- "type": "bytes4[1]"
27
- }
28
- ],
29
- "stateMutability": "payable",
30
- "type": "constructor"
31
- },
32
- {
33
- "inputs": [
34
- {
35
- "internalType": "address",
36
- "name": "caller",
37
- "type": "address"
38
- }
39
- ],
40
- "name": "AccessManagedUnauthorized",
41
- "type": "error"
42
- },
43
- {
44
- "inputs": [
45
- {
46
- "internalType": "address",
47
- "name": "target",
48
- "type": "address"
49
- }
50
- ],
51
- "name": "AddressEmptyCode",
52
- "type": "error"
53
- },
54
- {
55
- "inputs": [
56
- {
57
- "internalType": "address",
58
- "name": "implementation",
59
- "type": "address"
60
- }
61
- ],
62
- "name": "ERC1967InvalidImplementation",
63
- "type": "error"
64
- },
65
- {
66
- "inputs": [],
67
- "name": "ERC1967NonPayable",
68
- "type": "error"
69
- },
70
- {
71
- "inputs": [],
72
- "name": "FailedCall",
73
- "type": "error"
74
- },
75
- {
76
- "anonymous": false,
77
- "inputs": [
78
- {
79
- "indexed": true,
80
- "internalType": "address",
81
- "name": "implementation",
82
- "type": "address"
83
- }
84
- ],
85
- "name": "Upgraded",
86
- "type": "event"
87
- },
88
- {
89
- "stateMutability": "payable",
90
- "type": "fallback"
91
- },
92
- {
93
- "inputs": [],
94
- "name": "ACCESS_MANAGER",
95
- "outputs": [
96
- {
97
- "internalType": "contract IAccessManager",
98
- "name": "",
99
- "type": "address"
100
- }
101
- ],
102
- "stateMutability": "view",
103
- "type": "function"
104
- },
105
- {
106
- "inputs": [],
107
- "name": "PASS_THRU_METHODS",
108
- "outputs": [
109
- {
110
- "internalType": "bytes4[]",
111
- "name": "methods",
112
- "type": "bytes4[]"
113
- }
114
- ],
115
- "stateMutability": "view",
116
- "type": "function"
117
- }
118
- ],
119
- "bytecode": "0x60c060405260405161081638038061081683398101604081905261002291610336565b83838382826100318282610058565b50506001600160a01b03166080525050516001600160e01b03191660a05250610413915050565b610061826100b6565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156100aa576100a58282610131565b505050565b6100b26101a4565b5050565b806001600160a01b03163b5f036100f057604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b03168460405161014d91906103fd565b5f60405180830381855af49150503d805f8114610185576040519150601f19603f3d011682016040523d82523d5f602084013e61018a565b606091505b50909250905061019b8583836101c5565b95945050505050565b34156101c35760405163b398979f60e01b815260040160405180910390fd5b565b6060826101da576101d582610224565b61021d565b81511580156101f157506001600160a01b0384163b155b1561021a57604051639996b31560e01b81526001600160a01b03851660048201526024016100e7565b50805b9392505050565b80511561023357805160208201fd5b60405163d6bda27560e01b815260040160405180910390fd5b50565b6001600160a01b038116811461024c575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561029f5761029f610263565b604052919050565b80516102b28161024f565b919050565b5f82601f8301126102c6575f5ffd5b604051602081016001600160401b03811182821017156102e8576102e8610263565b6040528060208401858111156102fc575f5ffd5b845b8181101561032b5780516001600160e01b03198116811461031d575f5ffd5b8352602092830192016102fe565b509195945050505050565b5f5f5f5f60808587031215610349575f5ffd5b84516103548161024f565b60208601519094506001600160401b0381111561036f575f5ffd5b8501601f8101871361037f575f5ffd5b80516001600160401b0381111561039857610398610263565b6103ab601f8201601f1916602001610277565b8181528860208385010111156103bf575f5ffd5b8160208401602083015e5f602083830101528095505050506103e3604086016102a7565b91506103f286606087016102b7565b905092959194509250565b5f82518060208501845e5f920191825250919050565b60805160a0516103d66104405f395f818160dd015261017c01525f8181606d01526101db01526103d65ff3fe608060405260043610610028575f3560e01c806314416c03146100325780633a7b7a391461005c575b6100306100a7565b005b34801561003d575f5ffd5b506100466100b9565b604051610053919061029d565b60405180910390f35b348015610067575f5ffd5b5061008f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610053565b6100b76100b261012a565b610161565b565b604080516001808252818301909252606091602080830190803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000815f8151811061010e5761010e6102e9565b6001600160e01b03199092166020928302919091019091015290565b5f61015c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b5f61016f60048236816102fd565b61017891610324565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160e01b031990811690821614806102715760405163b700961360e01b81523360048201523060248201526001600160e01b0319831660448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b7009613906064016040805180830381865afa158015610227573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061024b919061035c565b509050806102715760405162d1953b60e31b815233600482015260240160405180910390fd5b61027a8361027f565b505050565b365f5f375f5f365f845af43d5f5f3e808015610299573d5ff35b3d5ffd5b602080825282518282018190525f918401906040840190835b818110156102de5783516001600160e01b0319168352602093840193909201916001016102b6565b509095945050505050565b634e487b7160e01b5f52603260045260245ffd5b5f5f8585111561030b575f5ffd5b83861115610317575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015610355576001600160e01b0319600485900360031b81901b82161691505b5092915050565b5f5f6040838503121561036d575f5ffd5b8251801515811461037c575f5ffd5b602084015190925063ffffffff81168114610395575f5ffd5b80915050925092905056fea2646970667358221220873e8348d7827c642661807395e7a3cf310474fd71de0b76f6468d17b66de4ac64736f6c634300081c0033",
120
- "deployedBytecode": "0x608060405260043610610028575f3560e01c806314416c03146100325780633a7b7a391461005c575b6100306100a7565b005b34801561003d575f5ffd5b506100466100b9565b604051610053919061029d565b60405180910390f35b348015610067575f5ffd5b5061008f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610053565b6100b76100b261012a565b610161565b565b604080516001808252818301909252606091602080830190803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000815f8151811061010e5761010e6102e9565b6001600160e01b03199092166020928302919091019091015290565b5f61015c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b5f61016f60048236816102fd565b61017891610324565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160e01b031990811690821614806102715760405163b700961360e01b81523360048201523060248201526001600160e01b0319831660448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b7009613906064016040805180830381865afa158015610227573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061024b919061035c565b509050806102715760405162d1953b60e31b815233600482015260240160405180910390fd5b61027a8361027f565b505050565b365f5f375f5f365f845af43d5f5f3e808015610299573d5ff35b3d5ffd5b602080825282518282018190525f918401906040840190835b818110156102de5783516001600160e01b0319168352602093840193909201916001016102b6565b509095945050505050565b634e487b7160e01b5f52603260045260245ffd5b5f5f8585111561030b575f5ffd5b83861115610317575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015610355576001600160e01b0319600485900360031b81901b82161691505b5092915050565b5f5f6040838503121561036d575f5ffd5b8251801515811461037c575f5ffd5b602084015190925063ffffffff81168114610395575f5ffd5b80915050925092905056fea2646970667358221220873e8348d7827c642661807395e7a3cf310474fd71de0b76f6468d17b66de4ac64736f6c634300081c0033",
121
- "linkReferences": {},
122
- "deployedLinkReferences": {}
123
- }