Skip to content

Commit 6a007e0

Browse files
author
Kansas
authored
Merge branch 'OpenZeppelin:master' into master
2 parents 29dff1f + b9c7078 commit 6a007e0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1493
-200
lines changed

.changeset/itchy-turkeys-allow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`RLP`: Add a library for encoding and decoding data in Ethereum's Recursive Length Prefix format.

.changeset/modern-moments-raise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`Memory`: Add a UDVT for handling slices on memory space similarly to calldata slices.

.changeset/shiny-dolphins-lick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`ERC4626`: compute `maxWithdraw` using `maxRedeem` and `previewRedeem` so that changes to the preview functions affect the max functions.

.changeset/silent-zebras-press.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`ERC7786Recipient`: Generic ERC-7786 cross-chain message recipient contract.

.changeset/wise-webs-fly.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`Accumulators`: A library for merging an arbitrary dynamic number of bytes buffers.

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66

77
### Breaking changes
88

9-
- Update minimum pragma to 0.8.24 in `Votes`, `VotesExtended`, `ERC20Votes`, `Strings`, `ERC1155URIStorage`, `MessageHashUtils`, `ERC721URIStorage`, `ERC721Votes`, `ERC721Wrapper`, `ERC721Burnable`, `ERC721Consecutive`, `ERC721Enumerable`, `ERC721Pausable`, `ERC721Royalty`, `ERC721Wrapper`, `EIP712`, and `ERC7739`. ([#5726](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5726))
9+
- `SignerERC7702` is renamed as `SignerEIP7702`. Imports and inheritance must be updated to that new name and path. Behavior is unmodified.
10+
- `ERC721Holder` and `ERC1155Holder` are flagged as stateless and are no longer transpiled. Developers using their upgradeable variants from `@openzeppelin/contracts-upgradeable` (i.e. `ERC712HolderUpgradeable` and `ERC1155HolderUpgradeable`) must update their imports to use the equivalent version available in `@openzeppelin/contracts`.
11+
- Update minimum pragma to 0.8.24 in `Votes`, `VotesExtended`, `ERC20Votes`, `Strings`, `ERC1155URIStorage`, `MessageHashUtils`, `ERC721URIStorage`, `ERC721Votes`, `ERC721Wrapper`, `ERC721Burnable`, `ERC721Consecutive`, `ERC721Enumerable`, `ERC721Pausable`, `ERC721Royalty`, `ERC721Wrapper`, `EIP712`, `ERC4626` and `ERC7739`. ([#5726](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5726))
1012

1113
### Deprecation
1214

15+
- `Initializable` and `UUPSUpgradeable` are no longer transpiled. An alias is present in the `@openzeppelin/contracts-upgradeable` package that redirect to the corresponding file in `@openzeppelin/contracts`. These alias will be removed in the next major release. Developers are advised to update their imports to get these files directly from the `@openzeppelin/contracts` package.
1316
- `ECDSA` signature malleability protection is partly deprecated. See documentation for more details.
1417

1518
## 5.4.0 (2025-07-17)

GUIDELINES.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ In addition to the official Solidity Style Guide we have a number of other conve
117117

118118
Some standards (e.g. ERC-20) use present tense, and in those cases the
119119
standard specification is used.
120-
120+
121121
* Interface names should have a capital I prefix.
122122

123123
```solidity
@@ -141,7 +141,7 @@ In addition to the official Solidity Style Guide we have a number of other conve
141141
* Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted.
142142

143143
* Custom errors should be declared following the [EIP-6093](https://eips.ethereum.org/EIPS/eip-6093) rationale whenever reasonable. Also, consider the following:
144-
144+
145145
* The domain prefix should be picked in the following order:
146146
1. Use `ERC<number>` if the error is a violation of an ERC specification.
147147
2. Use the name of the underlying component where it belongs (eg. `Governor`, `ECDSA`, or `Timelock`).
@@ -153,3 +153,18 @@ In addition to the official Solidity Style Guide we have a number of other conve
153153
4. Declare the error in an extension if the error only happens in such extension or child contracts.
154154

155155
* Custom error names should not be declared twice along the library to avoid duplicated identifier declarations when inheriting from multiple contracts.
156+
157+
* Numeric literals should use appropriate formats based on their purpose to improve code readability:
158+
159+
**Memory-related operations (use hexadecimal):**
160+
* Memory locations: `mload(64)``mload(0x40)`
161+
* Memory offsets: `mstore(add(ptr, 32), value)``mstore(add(ptr, 0x20), value)`
162+
* Memory lengths: `keccak256(ptr, 85)``keccak256(ptr, 0x55)`
163+
164+
**Bit operations (use decimal):**
165+
* Shift amounts: `shl(0x80, value)``shl(128, value)`
166+
* Bit masks and positions should use decimal when representing bit counts
167+
168+
**Exceptions:**
169+
* Trivially small values (1, 2) may use decimal even in memory operations: `ptr := add(ptr, 1)`
170+
* In `call`/`staticcall`/`delegatecall`, decimal zero is acceptable when both location and length are zero

contracts/account/utils/draft-ERC7579Utils.sol

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,10 @@ library ERC7579Utils {
126126
Mode mode
127127
) internal pure returns (CallType callType, ExecType execType, ModeSelector selector, ModePayload payload) {
128128
return (
129-
CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0)),
130-
ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 1)),
131-
ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 6)),
132-
ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 10))
129+
CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0x00)),
130+
ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0x01)),
131+
ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 0x06)),
132+
ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 0x0a))
133133
);
134134
}
135135

@@ -146,9 +146,9 @@ library ERC7579Utils {
146146
function decodeSingle(
147147
bytes calldata executionCalldata
148148
) internal pure returns (address target, uint256 value, bytes calldata callData) {
149-
target = address(bytes20(executionCalldata[0:20]));
150-
value = uint256(bytes32(executionCalldata[20:52]));
151-
callData = executionCalldata[52:];
149+
target = address(bytes20(executionCalldata[0x00:0x14]));
150+
value = uint256(bytes32(executionCalldata[0x14:0x34]));
151+
callData = executionCalldata[0x34:];
152152
}
153153

154154
/// @dev Encodes a delegate call execution. See {decodeDelegate}.
@@ -163,8 +163,8 @@ library ERC7579Utils {
163163
function decodeDelegate(
164164
bytes calldata executionCalldata
165165
) internal pure returns (address target, bytes calldata callData) {
166-
target = address(bytes20(executionCalldata[0:20]));
167-
callData = executionCalldata[20:];
166+
target = address(bytes20(executionCalldata[0:0x14]));
167+
callData = executionCalldata[0x14:];
168168
}
169169

170170
/// @dev Encodes a batch of executions. See {decodeBatch}.
@@ -180,17 +180,17 @@ library ERC7579Utils {
180180
uint256 bufferLength = executionCalldata.length;
181181

182182
// Check executionCalldata is not empty.
183-
if (bufferLength < 32) revert ERC7579DecodingError();
183+
if (bufferLength < 0x20) revert ERC7579DecodingError();
184184

185185
// Get the offset of the array (pointer to the array length).
186-
uint256 arrayLengthOffset = uint256(bytes32(executionCalldata[0:32]));
186+
uint256 arrayLengthOffset = uint256(bytes32(executionCalldata[0x00:0x20]));
187187

188188
// The array length (at arrayLengthOffset) should be 32 bytes long. We check that this is within the
189189
// buffer bounds. Since we know bufferLength is at least 32, we can subtract with no overflow risk.
190-
if (arrayLengthOffset > bufferLength - 32) revert ERC7579DecodingError();
190+
if (arrayLengthOffset > bufferLength - 0x20) revert ERC7579DecodingError();
191191

192192
// Get the array length. arrayLengthOffset + 32 is bounded by bufferLength so it does not overflow.
193-
uint256 arrayLength = uint256(bytes32(executionCalldata[arrayLengthOffset:arrayLengthOffset + 32]));
193+
uint256 arrayLength = uint256(bytes32(executionCalldata[arrayLengthOffset:arrayLengthOffset + 0x20]));
194194

195195
// Check that the buffer is long enough to store the array elements as "offset pointer":
196196
// - each element of the array is an "offset pointer" to the data.
@@ -200,7 +200,7 @@ library ERC7579Utils {
200200
//
201201
// Since we know bufferLength is at least arrayLengthOffset + 32, we can subtract with no overflow risk.
202202
// Solidity limits length of such arrays to 2**64-1, this guarantees `arrayLength * 32` does not overflow.
203-
if (arrayLength > type(uint64).max || bufferLength - arrayLengthOffset - 32 < arrayLength * 32)
203+
if (arrayLength > type(uint64).max || bufferLength - arrayLengthOffset - 0x20 < arrayLength * 0x20)
204204
revert ERC7579DecodingError();
205205

206206
assembly ("memory-safe") {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.27;
4+
5+
import {IERC7786Recipient} from "../interfaces/draft-IERC7786.sol";
6+
import {BitMaps} from "../utils/structs/BitMaps.sol";
7+
8+
/**
9+
* @dev Base implementation of an ERC-7786 compliant cross-chain message receiver.
10+
*
11+
* This abstract contract exposes the `receiveMessage` function that is used for communication with (one or multiple)
12+
* destination gateways. This contract leaves two functions unimplemented:
13+
*
14+
* * {_isAuthorizedGateway}, an internal getter used to verify whether an address is recognised by the contract as a
15+
* valid ERC-7786 destination gateway. One or multiple gateway can be supported. Note that any malicious address for
16+
* which this function returns true would be able to impersonate any account on any other chain sending any message.
17+
*
18+
* * {_processMessage}, the internal function that will be called with any message that has been validated.
19+
*
20+
* This contract implements replay protection, meaning that if two messages are received from the same gateway with the
21+
* same `receiveId`, then the second one will NOT be executed, regardless of the result of {_isAuthorizedGateway}.
22+
*/
23+
abstract contract ERC7786Recipient is IERC7786Recipient {
24+
using BitMaps for BitMaps.BitMap;
25+
26+
mapping(address gateway => BitMaps.BitMap) private _received;
27+
28+
error ERC7786RecipientUnauthorizedGateway(address gateway, bytes sender);
29+
error ERC7786RecipientMessageAlreadyProcessed(address gateway, bytes32 receiveId);
30+
31+
/// @inheritdoc IERC7786Recipient
32+
function receiveMessage(
33+
bytes32 receiveId,
34+
bytes calldata sender, // Binary Interoperable Address
35+
bytes calldata payload
36+
) external payable returns (bytes4) {
37+
// Check authorization
38+
if (!_isAuthorizedGateway(msg.sender, sender)) {
39+
revert ERC7786RecipientUnauthorizedGateway(msg.sender, sender);
40+
}
41+
42+
// Prevent duplicate execution
43+
if (_received[msg.sender].get(uint256(receiveId))) {
44+
revert ERC7786RecipientMessageAlreadyProcessed(msg.sender, receiveId);
45+
}
46+
_received[msg.sender].set(uint256(receiveId));
47+
48+
_processMessage(msg.sender, receiveId, sender, payload);
49+
50+
return IERC7786Recipient.receiveMessage.selector;
51+
}
52+
53+
/**
54+
* @dev Virtual getter that returns whether an address is a valid ERC-7786 gateway for a given sender.
55+
*
56+
* The `sender` parameter is an interoperable address that include the source chain. The chain part can be
57+
* extracted using the {InteroperableAddress} library to selectively authorize gateways based on the origin chain
58+
* of a message.
59+
*/
60+
function _isAuthorizedGateway(address gateway, bytes calldata sender) internal view virtual returns (bool);
61+
62+
/// @dev Virtual function that should contain the logic to execute when a cross-chain message is received.
63+
function _processMessage(
64+
address gateway,
65+
bytes32 receiveId,
66+
bytes calldata sender,
67+
bytes calldata payload
68+
) internal virtual;
69+
}

contracts/crosschain/README.adoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
= Cross chain interoperability
2+
3+
[.readme-notice]
4+
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/crosschain
5+
6+
This directory contains contracts for sending and receiving cross chain messages that follows the ERC-7786 standard.
7+
8+
- {ERC7786Recipient}: generic ERC-7786 crosschain contract that receives messages from a trusted gateway
9+
10+
== Helpers
11+
12+
{{ERC7786Recipient}}

0 commit comments

Comments
 (0)