Skip to content

Commit

Permalink
Merge branch 'feat/access-manager'
Browse files Browse the repository at this point in the history
  • Loading branch information
frangio committed Sep 19, 2023
2 parents 6820476 + 64da2c1 commit f7db0be
Show file tree
Hide file tree
Showing 86 changed files with 3,987 additions and 370 deletions.
5 changes: 5 additions & 0 deletions .changeset/empty-cheetahs-hunt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': major
---

`ERC721URIStorage`: Allow setting the token URI prior to minting.
5 changes: 5 additions & 0 deletions .changeset/fair-humans-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': major
---

`ERC721URIStorage`, `ERC721Royalty`: Stop resetting token-specific URI and royalties when burning.
5 changes: 5 additions & 0 deletions .changeset/large-humans-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': patch
---

`MerkleProof`: Use custom error to report invalid multiproof instead of reverting with overflow panic.
5 changes: 5 additions & 0 deletions .changeset/lazy-rice-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`Initializable`: Use intermediate variables to improve readability.
5 changes: 5 additions & 0 deletions .changeset/proud-spiders-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': major
---

`ERC721`: Renamed `_requireMinted` to `_requireOwned` and added a return value with the current owner. Implemented `ownerOf` in terms of `_requireOwned`.
5 changes: 5 additions & 0 deletions .changeset/quiet-trainers-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`AccessManager`: Added a new contract for managing access control of complex systems in a consolidated location.
5 changes: 5 additions & 0 deletions .changeset/violet-melons-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': major
---

`GovernorTimelockAccess`: Added a module to connect a governor with an instance of `AccessManager`, allowing the governor to make calls that are delay-restricted by the manager using the normal `queue` workflow.
2 changes: 2 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jobs:
run: npm run test:generation
- name: Compare gas costs
uses: ./.github/actions/gas-compare
if: github.base_ref == 'master'
with:
token: ${{ github.token }}

Expand All @@ -63,6 +64,7 @@ jobs:
run: npm run test:inheritance
- name: Check storage layout
uses: ./.github/actions/storage-layout
if: github.base_ref == 'master'
continue-on-error: ${{ contains(github.event.pull_request.labels.*.name, 'breaking change') }}
with:
token: ${{ github.token }}
Expand Down
10 changes: 10 additions & 0 deletions contracts/access/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,13 @@ This directory provides ways to restrict who can access the functions of a contr
{{IAccessControlDefaultAdminRules}}

{{AccessControlDefaultAdminRules}}

== AccessManager

{{IAuthority}}

{{AccessManager}}

{{AccessManaged}}

{{AccessManagerAdapter}}
121 changes: 121 additions & 0 deletions contracts/access/manager/AccessManaged.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {IAuthority} from "./IAuthority.sol";
import {AuthorityUtils} from "./AuthorityUtils.sol";
import {IAccessManager} from "./IAccessManager.sol";
import {IAccessManaged} from "./IAccessManaged.sol";
import {Context} from "../../utils/Context.sol";

/**
* @dev This contract module makes available a {restricted} modifier. Functions decorated with this modifier will be
* permissioned according to an "authority": a contract like {AccessManager} that follows the {IAuthority} interface,
* implementing a policy that allows certain callers to access certain functions.
*
* IMPORTANT: The `restricted` modifier should never be used on `internal` functions, judiciously used in `public`
* functions, and ideally only used in `external` functions. See {restricted}.
*/
abstract contract AccessManaged is Context, IAccessManaged {
address private _authority;

bool private _consumingSchedule;

/**
* @dev Initializes the contract connected to an initial authority.
*/
constructor(address initialAuthority) {
_setAuthority(initialAuthority);
}

/**
* @dev Restricts access to a function as defined by the connected Authority for this contract and the
* caller and selector of the function that entered the contract.
*
* [IMPORTANT]
* ====
* In general, this modifier should only be used on `external` functions. It is okay to use it on `public`
* functions that are used as external entry points and are not called internally. Unless you know what you're
* doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security
* implications! This is because the permissions are determined by the function that entered the contract, i.e. the
* function at the bottom of the call stack, and not the function where the modifier is visible in the source code.
* ====
*
* [NOTE]
* ====
* Selector collisions are mitigated by scoping permissions per contract, but some edge cases must be considered:
*
* * If the https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function[`receive()`] function
* is restricted, any other function with a `0x00000000` selector will share permissions with `receive()`.
* * Similarly, if there's no `receive()` function but a `fallback()` instead, the fallback might be called with
* empty `calldata`, sharing the `0x00000000` selector permissions as well.
* * For any other selector, if the restricted function is set on an upgradeable contract, an upgrade may remove
* the restricted function and replace it with a new method whose selector replaces the last one, keeping the
* previous permissions.
* ====
*/
modifier restricted() {
_checkCanCall(_msgSender(), _msgData());
_;
}

/**
* @dev Returns the current authority.
*/
function authority() public view virtual returns (address) {
return _authority;
}

/**
* @dev Transfers control to a new authority. The caller must be the current authority.
*/
function setAuthority(address newAuthority) public virtual {
address caller = _msgSender();
if (caller != authority()) {
revert AccessManagedUnauthorized(caller);
}
if (newAuthority.code.length == 0) {
revert AccessManagedInvalidAuthority(newAuthority);
}
_setAuthority(newAuthority);
}

/**
* @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is
* being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs
* attacker controlled calls.
*/
function isConsumingScheduledOp() public view returns (bytes4) {
return _consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0);
}

/**
* @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the
* permissions set by the current authority.
*/
function _setAuthority(address newAuthority) internal virtual {
_authority = newAuthority;
emit AuthorityUpdated(newAuthority);
}

/**
* @dev Reverts if the caller is not allowed to call the function identified by a selector.
*/
function _checkCanCall(address caller, bytes calldata data) internal virtual {
(bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay(
authority(),
caller,
address(this),
bytes4(data)
);
if (!immediate) {
if (delay > 0) {
_consumingSchedule = true;
IAccessManager(authority()).consumeScheduledOp(caller, data);
_consumingSchedule = false;
} else {
revert AccessManagedUnauthorized(caller);
}
}
}
}
Loading

0 comments on commit f7db0be

Please sign in to comment.