@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.
- package/README.md +47 -4
- package/build/build-info.json +1 -1
- package/build/contracts/AMPUtils.sol/AMPUtils.json +22 -0
- package/build/contracts/AccessManagedProxy.sol/AccessManagedProxy.json +71 -3
- package/build/contracts/AccessManagedProxyBase.sol/AccessManagedProxyBase.json +147 -0
- package/build/contracts/interfaces/IAccessManagedProxy.sol/IAccessManagedProxy.json +98 -0
- package/build/contracts/mock/DummyAccessManaged.sol/DummyAccessManaged.json +321 -0
- package/build/contracts/mock/DummyImplementation.sol/DummyImplementation.json +95 -2
- package/contracts/AMPUtils.sol +88 -0
- package/contracts/AccessManagedProxy.sol +39 -51
- package/contracts/AccessManagedProxyBase.sol +74 -0
- package/contracts/interfaces/IAccessManagedProxy.sol +51 -0
- package/contracts/mock/DummyAccessManaged.sol +56 -0
- package/contracts/mock/DummyImplementation.sol +19 -2
- package/js/deployProxy.js +69 -0
- package/package.json +1 -1
- package/build/contracts/amps/AccessManagedProxyS1.sol/AccessManagedProxyS1.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS10.sol/AccessManagedProxyS10.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS11.sol/AccessManagedProxyS11.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS12.sol/AccessManagedProxyS12.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS13.sol/AccessManagedProxyS13.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS14.sol/AccessManagedProxyS14.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS15.sol/AccessManagedProxyS15.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS16.sol/AccessManagedProxyS16.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS17.sol/AccessManagedProxyS17.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS18.sol/AccessManagedProxyS18.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS19.sol/AccessManagedProxyS19.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS2.sol/AccessManagedProxyS2.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS20.sol/AccessManagedProxyS20.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS21.sol/AccessManagedProxyS21.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS22.sol/AccessManagedProxyS22.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS23.sol/AccessManagedProxyS23.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS24.sol/AccessManagedProxyS24.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS3.sol/AccessManagedProxyS3.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS4.sol/AccessManagedProxyS4.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS5.sol/AccessManagedProxyS5.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS6.sol/AccessManagedProxyS6.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS7.sol/AccessManagedProxyS7.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS8.sol/AccessManagedProxyS8.json +0 -123
- package/build/contracts/amps/AccessManagedProxyS9.sol/AccessManagedProxyS9.json +0 -123
- package/contracts/amps/AccessManagedProxyS1.sol +0 -63
- package/contracts/amps/AccessManagedProxyS10.sol +0 -99
- package/contracts/amps/AccessManagedProxyS11.sol +0 -103
- package/contracts/amps/AccessManagedProxyS12.sol +0 -107
- package/contracts/amps/AccessManagedProxyS13.sol +0 -111
- package/contracts/amps/AccessManagedProxyS14.sol +0 -115
- package/contracts/amps/AccessManagedProxyS15.sol +0 -119
- package/contracts/amps/AccessManagedProxyS16.sol +0 -123
- package/contracts/amps/AccessManagedProxyS17.sol +0 -127
- package/contracts/amps/AccessManagedProxyS18.sol +0 -131
- package/contracts/amps/AccessManagedProxyS19.sol +0 -135
- package/contracts/amps/AccessManagedProxyS2.sol +0 -67
- package/contracts/amps/AccessManagedProxyS20.sol +0 -139
- package/contracts/amps/AccessManagedProxyS21.sol +0 -143
- package/contracts/amps/AccessManagedProxyS22.sol +0 -147
- package/contracts/amps/AccessManagedProxyS23.sol +0 -151
- package/contracts/amps/AccessManagedProxyS24.sol +0 -155
- package/contracts/amps/AccessManagedProxyS3.sol +0 -71
- package/contracts/amps/AccessManagedProxyS4.sol +0 -75
- package/contracts/amps/AccessManagedProxyS5.sol +0 -79
- package/contracts/amps/AccessManagedProxyS6.sol +0 -83
- package/contracts/amps/AccessManagedProxyS7.sol +0 -87
- package/contracts/amps/AccessManagedProxyS8.sol +0 -91
- package/contracts/amps/AccessManagedProxyS9.sol +0 -95
|
@@ -1,85 +1,73 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
-
*
|
|
14
|
-
*
|
|
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
|
-
*
|
|
17
|
-
*
|
|
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
|
|
26
|
-
|
|
27
|
-
|
|
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 `
|
|
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
|
|
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
|
-
*
|
|
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
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
58
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// solhint-disable-next-line
|
|
82
|
-
function
|
|
83
|
-
return
|
|
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 {
|
|
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,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
|
-
}
|