Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

### Pragma changes

- Reduced pragma requirement of interface files
- Reduced pragma requirement of interface files.

### Changes by category

Expand Down
4 changes: 2 additions & 2 deletions contracts/metatx/ERC2771Forwarder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {Errors} from "../utils/Errors.sol";
* * `to`: The address that should be called.
* * `value`: The amount of native token to attach with the requested call.
* * `gas`: The amount of gas limit that will be forwarded with the requested call.
* * `nonce`: A unique transaction ordering identifier to avoid replayability and request invalidation.
* * `nonce` (implicit): Taken from {Nonces} for `from` and included in the signed typed data.
* * `deadline`: A timestamp after which the request is not executable anymore.
* * `data`: Encoded `msg.data` to send with the requested call.
*
Expand Down Expand Up @@ -195,7 +195,7 @@ contract ERC2771Forwarder is EIP712, Nonces {

/**
* @dev Validates if the provided request can be executed at current block timestamp with
* the given `request.signature` on behalf of `request.signer`.
* the given `request.signature` on behalf of `request.from`.
*/
function _validate(
ForwardRequestData calldata request
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/docs/ERC4626Fees.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ abstract contract ERC4626Fees is ERC4626 {
}
}

/// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_deposit}.
/// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_withdraw}.
function _withdraw(
address caller,
address receiver,
Expand Down
4 changes: 2 additions & 2 deletions contracts/token/ERC20/extensions/ERC4626.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ abstract contract ERC4626 is ERC20, IERC4626 {
error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max);

/**
* @dev Attempted to withdraw more assets than the max amount for `receiver`.
* @dev Attempted to withdraw more assets than the max amount for `owner`.
*/
error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max);

/**
* @dev Attempted to redeem more shares than the max amount for `receiver`.
* @dev Attempted to redeem more shares than the max amount for `owner`.
*/
error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max);

Expand Down
4 changes: 2 additions & 2 deletions contracts/utils/cryptography/SignatureChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ library SignatureChecker {
// Encoded calldata is :
// [ 0x00 - 0x03 ] <selector>
// [ 0x04 - 0x23 ] <hash>
// [ 0x24 - 0x44 ] <signature offset> (0x40)
// [ 0x44 - 0x64 ] <signature length>
// [ 0x24 - 0x43 ] <signature offset> (0x40)
// [ 0x44 - 0x63 ] <signature length>
// [ 0x64 - ... ] <signature data>
let ptr := mload(0x40)
mstore(ptr, selector)
Expand Down
6 changes: 3 additions & 3 deletions contracts/utils/math/SafeCast.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ pragma solidity ^0.8.20;
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
* @dev Value doesn't fit in a uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

/**
* @dev An int value doesn't fit in an uint of `bits` size.
* @dev An int value doesn't fit in a uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);

Expand All @@ -33,7 +33,7 @@ library SafeCast {
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

/**
* @dev An uint value doesn't fit in an int of `bits` size.
* @dev A uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);

Expand Down
8 changes: 5 additions & 3 deletions docs/modules/ROOT/pages/access-control.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ In this way, you can use _composability_ to add additional layers of access cont
[[role-based-access-control]]
== Role-Based Access Control

While the simplicity of _ownership_ can be useful for simple systems or quick prototyping, different levels of authorization are often needed. You may want for an account to have permission to ban users from a system, but not create new tokens. https://en.wikipedia.org/wiki/Role-based_access_control[_Role-Based Access Control (RBAC)_] offers flexibility in this regard.
While the simplicity of _ownership_ can be useful for simple systems or quick prototyping, different levels of authorization are often needed. You may want an account to have permission to ban users from a system, but not create new tokens. https://en.wikipedia.org/wiki/Role-based_access_control[_Role-Based Access Control (RBAC)_] offers flexibility in this regard.

In essence, we will be defining multiple _roles_, each allowed to perform different sets of actions. An account may have, for example, 'moderator', 'minter' or 'admin' roles, which you will then check for instead of simply using `onlyOwner`. This check can be enforced through the `onlyRole` modifier. Separately, you will be able to define rules for how accounts can be granted a role, have it revoked, and more.

Expand Down Expand Up @@ -74,7 +74,7 @@ Every role has an associated admin role, which grants permission to call the `gr

This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also provides an easy way to manage simpler applications. `AccessControl` includes a special role, called `DEFAULT_ADMIN_ROLE`, which acts as the **default admin role for all roles**. An account with this role will be able to manage any other role, unless `_setRoleAdmin` is used to select a new admin role.

Since it is the admin for all roles by default, and in fact it is also its own admin, this role carries significant risk. To mitigate this risk we provide xref:api:access.adoc#AccessControlDefaultAdminRules[`AccessControlDefaultAdminRules`], a recommended extension of `AccessControl` that adds a number of enforced security measures for this role: the admin is restricted to a single account, with a 2-step transfer procedure with a delay in between steps.
Since it is the admin for all roles by default, and in fact it is also its own admin, this role carries significant risk. To mitigate this risk we provide xref:api:access.adoc#AccessControlDefaultAdminRules[`AccessControlDefaultAdminRules`], a recommended extension of `AccessControl` that adds a number of enforced security measures for this role: the admin is restricted to a single account, with a 2-step transfer procedure with a delay between steps.

Let's take a look at the ERC-20 token example, this time taking advantage of the default admin role:

Expand Down Expand Up @@ -199,7 +199,7 @@ await manager.setTargetFunctionRole(
);
```

Even though each role has its own list of function permissions, each role member (`address`) has an execution delay that will dictate how long the account should wait to execute a function that requires its role. Delayed operations must have the xref:api:access.adoc#AccessManager-schedule-address-bytes-uint48-[`schedule`] function called on them first in the AccessManager before they can be executed, either by calling to the target function or using the AccessManager's xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] function.
Even though each role has its own list of function permissions, each role member (`address`) has an execution delay that will dictate how long the account should wait to execute a function that requires its role. Delayed operations must have the xref:api:access.adoc#AccessManager-schedule-address-bytes-uint48-[`schedule`] function called on them first in the AccessManager before they can be executed, either by calling the target function or using the AccessManager's xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] function.

Additionally, roles can have a granting delay that prevents adding members immediately. The AccessManager admins can set this grant delay as follows:

Expand Down Expand Up @@ -293,3 +293,5 @@ await accessControl.connect(admin).grantRole(DEFAULT_ADMIN_ROLE, accessManager);

await accessControl.connect(admin).renounceRole(DEFAULT_ADMIN_ROLE, admin);
```

NOTE: After migrating to AccessManager, the `msg.sender` in restricted functions will be the AccessManager contract itself through the xref:api:access.adoc#AccessManager-execute-address-bytes-[`execute`] function, not the original caller. This is a fundamental change in how access control works and may require updates to your contract logic or frontend integration.
8 changes: 4 additions & 4 deletions docs/modules/ROOT/pages/accounts.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

OpenZeppelin provides a simple xref:api:account.adoc#Account[`Account`] implementation including only the basic logic to handle user operations in compliance with ERC-4337. Developers who want to build their own account can leverage it to bootstrap custom implementations.

User operations are validated using an xref:api:utils.adoc#AbstractSigner[`AbstractSigner`], which requires to implement the internal xref:api:utils.adoc#AbstractSigner-_rawSignatureValidation-bytes32-bytes-[`_rawSignatureValidation`] function, of which we offer a set of implementations to cover a wide customization range. This is the lowest-level signature validation layer and is used to wrap other validation methods like the Account's xref:api:account.adoc#Account-validateUserOp-struct-PackedUserOperation-bytes32-uint256-[`validateUserOp`].
User operations are validated using an xref:api:utils.adoc#AbstractSigner[`AbstractSigner`], which requires implementing the internal xref:api:utils.adoc#AbstractSigner-_rawSignatureValidation-bytes32-bytes-[`_rawSignatureValidation`] function, of which we offer a set of implementations to cover a wide customization range. This is the lowest-level signature validation layer and is used to wrap other validation methods like the Account's xref:api:account.adoc#Account-validateUserOp-struct-PackedUserOperation-bytes32-uint256-[`validateUserOp`].

== Setting up an account

To setup an account, you can either start configuring it using our Wizard and selecting a predefined validation scheme, or bring your own logic and start by inheriting xref:api:account.adoc#Account[`Account`] from scratch.
To set up an account, you can either start configuring it using our Wizard and selecting a predefined validation scheme, or bring your own logic and start by inheriting xref:api:account.adoc#Account[`Account`] from scratch.

++++
<script async src="https://wizard.openzeppelin.com/build/embed.js"></script>
Expand All @@ -25,7 +25,7 @@ Since the minimum requirement of xref:api:account.adoc#Account[`Account`] is to
* xref:api:utils/cryptography.adoc#SignerRSA[`SignerRSA`]: Verifies signatures of traditional PKI systems and X.509 certificates.
* xref:api:utils/cryptography.adoc#SignerEIP7702[`SignerEIP7702`]: Checks EOA signatures delegated to this signer using https://eips.ethereum.org/EIPS/eip-7702#set-code-transaction[EIP-7702 authorizations]
* xref:api:utils/cryptography.adoc#SignerERC7913[`SignerERC7913`]: Verifies generalized signatures following https://eips.ethereum.org/EIPS/eip-7913[ERC-7913].
* https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#SignerZKEmail[`SignerZKEmail`]: Enables email-based authentication for smart contracts using zero knowledge proofs of email authority signatures.
* https://docs.openzeppelin.com/community-contracts/0.0.1/api/utils#SignerZKEmail[`SignerZKEmail`]: Enables email-based authentication for smart contracts using zero-knowledge proofs of email authority signatures.
* xref:api:utils/cryptography.adoc#MultiSignerERC7913[`MultiSignerERC7913`]: Allows using multiple ERC-7913 signers with a threshold-based signature verification system.
* xref:api:utils/cryptography.adoc#MultiSignerERC7913Weighted[`MultiSignerERC7913Weighted`]: Overrides the threshold mechanism of xref:api:utils/cryptography.adoc#MultiSignerERC7913[`MultiSignerERC7913`], offering different weights per signer.

Expand Down Expand Up @@ -153,7 +153,7 @@ const userOpData = encodeFunctionData({

== Bundle a `UserOperation`

xref:account-abstraction.adoc#useroperation[UserOperations] are a powerful abstraction layer that enable more sophisticated transaction capabilities compared to traditional Ethereum transactions. To get started, you'll need to an account, which you can get by xref:accounts.adoc#accounts_factory[deploying a factory] for your implementation.
xref:account-abstraction.adoc#useroperation[UserOperations] are a powerful abstraction layer that enable more sophisticated transaction capabilities compared to traditional Ethereum transactions. To get started, you'll need an account, which you can get by xref:accounts.adoc#accounts_factory[deploying a factory] for your implementation.

=== Preparing a UserOp

Expand Down
6 changes: 3 additions & 3 deletions scripts/generate/templates/SafeCast.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ pragma solidity ^0.8.20;

const errors = `\
/**
* @dev Value doesn't fit in an uint of \`bits\` size.
* @dev Value doesn't fit in a uint of \`bits\` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

/**
* @dev An int value doesn't fit in an uint of \`bits\` size.
* @dev An int value doesn't fit in a uint of \`bits\` size.
*/
error SafeCastOverflowedIntToUint(int256 value);

Expand All @@ -37,7 +37,7 @@ error SafeCastOverflowedIntToUint(int256 value);
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

/**
* @dev An uint value doesn't fit in an int of \`bits\` size.
* @dev A uint value doesn't fit in an int of \`bits\` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
`;
Expand Down
4 changes: 3 additions & 1 deletion scripts/minimize-pragma.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ const limit = pLimit(concurrency);
const updatePragma = (file, pragma) =>
fs.writeFileSync(
file,
fs.readFileSync(file, 'utf8').replace(/pragma solidity [><=^]*[0-9]+.[0-9]+.[0-9]+;/, `pragma solidity ${pragma};`),
fs
.readFileSync(file, 'utf8')
.replace(/pragma solidity [><=^]*[0-9]+\.[0-9]+\.[0-9]+;/, `pragma solidity ${pragma};`),
'utf8',
);

Expand Down
2 changes: 1 addition & 1 deletion test/access/manager/AccessManaged.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('AccessManaged', function () {

describe('when role is granted with execution delay', function () {
beforeEach(async function () {
const executionDelay = 911n;
const executionDelay = 911n; // Arbitrary delay for testing execution delay functionality
await this.authority.$_grantRole(this.role, this.roleMember, 0, executionDelay);
});

Expand Down