Skip to content

Commit d1289a2

Browse files
authored
Merge branch 'master' into lib-618-accesscontrol-admin-rules
2 parents b2b9e81 + 2c6ef8c commit d1289a2

File tree

18 files changed

+540
-26
lines changed

18 files changed

+540
-26
lines changed

.changeset/warm-masks-obey.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers.

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
- `ERC20Permit`: Added the file `IERC20Permit.sol` and `ERC20Permit.sol` and deprecated `draft-IERC20Permit.sol` and `draft-ERC20Permit.sol` since [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) is no longer a Draft. Developers are encouraged to update their imports. ([#3793](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3793))
1111
- `Timers`: The `Timers` library is now deprecated and will be removed in the next major release. ([#4062](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4062))
12+
- `ERC777`: The `ERC777` token standard is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066))
13+
- `ERC1820Implementer`: The `ERC1820` pseudo-introspection mechanism is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066))
1214

1315
## 4.8.1 (2023-01-12)
1416

contracts/governance/compatibility/GovernorCompatibilityBravo.sol

+6-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
5555
bytes[] memory calldatas,
5656
string memory description
5757
) public virtual override(IGovernor, Governor) returns (uint256) {
58+
// Stores the proposal details (if not already present) and executes the propose logic from the core.
5859
_storeProposal(_msgSender(), targets, values, new string[](calldatas.length), calldatas, description);
5960
return super.propose(targets, values, calldatas, description);
6061
}
@@ -69,6 +70,10 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
6970
bytes[] memory calldatas,
7071
string memory description
7172
) public virtual override returns (uint256) {
73+
// Stores the full proposal and fallback to the public (possibly overridden) propose. The fallback is done
74+
// after the full proposal is stored, so the store operation included in the fallback will be skipped. Here we
75+
// call `propose` and not `super.propose` to make sure if a child contract override `propose`, whatever code
76+
// is added their is also executed when calling this alternative interface.
7277
_storeProposal(_msgSender(), targets, values, signatures, calldatas, description);
7378
return propose(targets, values, _encodeCalldata(signatures, calldatas), description);
7479
}
@@ -174,7 +179,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
174179
}
175180

176181
/**
177-
* @dev Store proposal metadata for later lookup
182+
* @dev Store proposal metadata (if not already present) for later lookup.
178183
*/
179184
function _storeProposal(
180185
address proposer,

contracts/interfaces/IERC1363.sol

+3-8
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,12 @@ import "./IERC165.sol";
88

99
interface IERC1363 is IERC165, IERC20 {
1010
/*
11-
* Note: the ERC-165 identifier for this interface is 0x4bbee2df.
12-
* 0x4bbee2df ===
11+
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
12+
* 0xb0202a11 ===
1313
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
1414
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
1515
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
16-
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)'))
17-
*/
18-
19-
/*
20-
* Note: the ERC-165 identifier for this interface is 0xfb9ec8ce.
21-
* 0xfb9ec8ce ===
16+
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
2217
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
2318
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
2419
*/

contracts/interfaces/README.adoc

+14
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ are useful to interact with third party contracts that implement them.
2222
- {IERC1155MetadataURI}
2323
- {IERC1271}
2424
- {IERC1363}
25+
- {IERC1363Receiver}
26+
- {IERC1363Spender}
2527
- {IERC1820Implementer}
2628
- {IERC1820Registry}
2729
- {IERC1822Proxiable}
@@ -30,7 +32,11 @@ are useful to interact with third party contracts that implement them.
3032
- {IERC3156FlashLender}
3133
- {IERC3156FlashBorrower}
3234
- {IERC4626}
35+
- {IERC4906}
36+
- {IERC5267}
3337
- {IERC5313}
38+
- {IERC5805}
39+
- {IERC6372}
3440

3541
== Detailed ABI
3642

@@ -40,6 +46,8 @@ are useful to interact with third party contracts that implement them.
4046

4147
{{IERC1363Receiver}}
4248

49+
{{IERC1363Spender}}
50+
4351
{{IERC1820Implementer}}
4452

4553
{{IERC1820Registry}}
@@ -57,3 +65,9 @@ are useful to interact with third party contracts that implement them.
5765
{{IERC4626}}
5866

5967
{{IERC5313}}
68+
69+
{{IERC5267}}
70+
71+
{{IERC5805}}
72+
73+
{{IERC6372}}

contracts/mocks/docs/ERC4626Fees.sol

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import "../../token/ERC20/extensions/ERC4626.sol";
6+
7+
abstract contract ERC4626Fees is ERC4626 {
8+
using Math for uint256;
9+
10+
/** @dev See {IERC4626-previewDeposit}. */
11+
function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
12+
uint256 fee = _feeOnTotal(assets, _entryFeeBasePoint());
13+
return super.previewDeposit(assets - fee);
14+
}
15+
16+
/** @dev See {IERC4626-previewMint}. */
17+
function previewMint(uint256 shares) public view virtual override returns (uint256) {
18+
uint256 assets = super.previewMint(shares);
19+
return assets + _feeOnRaw(assets, _entryFeeBasePoint());
20+
}
21+
22+
/** @dev See {IERC4626-previewWithdraw}. */
23+
function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
24+
uint256 fee = _feeOnRaw(assets, _exitFeeBasePoint());
25+
return super.previewWithdraw(assets + fee);
26+
}
27+
28+
/** @dev See {IERC4626-previewRedeem}. */
29+
function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
30+
uint256 assets = super.previewRedeem(shares);
31+
return assets - _feeOnTotal(assets, _exitFeeBasePoint());
32+
}
33+
34+
/** @dev See {IERC4626-_deposit}. */
35+
function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override {
36+
uint256 fee = _feeOnTotal(assets, _entryFeeBasePoint());
37+
address recipient = _entryFeeRecipient();
38+
39+
super._deposit(caller, receiver, assets, shares);
40+
41+
if (fee > 0 && recipient != address(this)) {
42+
SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
43+
}
44+
}
45+
46+
/** @dev See {IERC4626-_deposit}. */
47+
function _withdraw(
48+
address caller,
49+
address receiver,
50+
address owner,
51+
uint256 assets,
52+
uint256 shares
53+
) internal virtual override {
54+
uint256 fee = _feeOnRaw(assets, _exitFeeBasePoint());
55+
address recipient = _exitFeeRecipient();
56+
57+
super._withdraw(caller, receiver, owner, assets, shares);
58+
59+
if (fee > 0 && recipient != address(this)) {
60+
SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
61+
}
62+
}
63+
64+
function _entryFeeBasePoint() internal view virtual returns (uint256) {
65+
return 0;
66+
}
67+
68+
function _entryFeeRecipient() internal view virtual returns (address) {
69+
return address(0);
70+
}
71+
72+
function _exitFeeBasePoint() internal view virtual returns (uint256) {
73+
return 0;
74+
}
75+
76+
function _exitFeeRecipient() internal view virtual returns (address) {
77+
return address(0);
78+
}
79+
80+
function _feeOnRaw(uint256 assets, uint256 feeBasePoint) private pure returns (uint256) {
81+
return assets.mulDiv(feeBasePoint, 1e5, Math.Rounding.Up);
82+
}
83+
84+
function _feeOnTotal(uint256 assets, uint256 feeBasePoint) private pure returns (uint256) {
85+
return assets.mulDiv(feeBasePoint, feeBasePoint + 1e5, Math.Rounding.Up);
86+
}
87+
}
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import "../docs/ERC4626Fees.sol";
6+
7+
abstract contract ERC4626FeesMock is ERC4626Fees {
8+
uint256 private immutable _entryFeeBasePointValue;
9+
address private immutable _entryFeeRecipientValue;
10+
uint256 private immutable _exitFeeBasePointValue;
11+
address private immutable _exitFeeRecipientValue;
12+
13+
constructor(
14+
uint256 entryFeeBasePoint,
15+
address entryFeeRecipient,
16+
uint256 exitFeeBasePoint,
17+
address exitFeeRecipient
18+
) {
19+
_entryFeeBasePointValue = entryFeeBasePoint;
20+
_entryFeeRecipientValue = entryFeeRecipient;
21+
_exitFeeBasePointValue = exitFeeBasePoint;
22+
_exitFeeRecipientValue = exitFeeRecipient;
23+
}
24+
25+
function _entryFeeBasePoint() internal view virtual override returns (uint256) {
26+
return _entryFeeBasePointValue;
27+
}
28+
29+
function _entryFeeRecipient() internal view virtual override returns (address) {
30+
return _entryFeeRecipientValue;
31+
}
32+
33+
function _exitFeeBasePoint() internal view virtual override returns (uint256) {
34+
return _exitFeeBasePointValue;
35+
}
36+
37+
function _exitFeeRecipient() internal view virtual override returns (address) {
38+
return _exitFeeRecipientValue;
39+
}
40+
}

contracts/token/ERC777/ERC777.sol

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import "../../utils/introspection/IERC1820Registry.sol";
2525
* Additionally, the {IERC777-granularity} value is hard-coded to `1`, meaning that there
2626
* are no special restrictions in the amount of tokens that created, moved, or
2727
* destroyed. This makes integration with ERC20 applications seamless.
28+
*
29+
* CAUTION: This file is deprecated as of v4.9 and will be removed in the next major release.
2830
*/
2931
contract ERC777 is Context, IERC777, IERC20 {
3032
using Address for address;

contracts/token/ERC777/README.adoc

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
[.readme-notice]
44
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc777
55

6+
CAUTION: As of v4.9, OpenZeppelin's implementation of ERC-777 is deprecated and will be removed in the next major release.
7+
68
This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-777[ERC777 token standard].
79

810
TIP: For an overview of ERC777 tokens and a walk through on how to create a token contract read our xref:ROOT:erc777.adoc[ERC777 guide].

contracts/utils/cryptography/EIP712.sol

-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ abstract contract EIP712 is IERC5267 {
3838
bytes32 private constant _TYPE_HASH =
3939
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
4040

41-
/* solhint-disable var-name-mixedcase */
4241
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
4342
// invalidate the cached domain separator if the chain id changes.
4443
bytes32 private immutable _cachedDomainSeparator;
@@ -53,8 +52,6 @@ abstract contract EIP712 is IERC5267 {
5352
bytes32 private immutable _hashedName;
5453
bytes32 private immutable _hashedVersion;
5554

56-
/* solhint-enable var-name-mixedcase */
57-
5855
/**
5956
* @dev Initializes the domain separator and parameter caches.
6057
*

contracts/utils/cryptography/SignatureChecker.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ library SignatureChecker {
4444
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
4545
);
4646
return (success &&
47-
result.length == 32 &&
47+
result.length >= 32 &&
4848
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
4949
}
5050
}

contracts/utils/introspection/ERC1820Implementer.sol

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import "./IERC1820Implementer.sol";
1212
* declare their willingness to be implementers.
1313
* {IERC1820Registry-setInterfaceImplementer} should then be called for the
1414
* registration to be complete.
15+
*
16+
* CAUTION: This file is deprecated as of v4.9 and will be removed in the next major release.
1517
*/
1618
contract ERC1820Implementer is IERC1820Implementer {
1719
bytes32 private constant _ERC1820_ACCEPT_MAGIC = keccak256("ERC1820_ACCEPT_MAGIC");

contracts/utils/math/Math.sol

+3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ library Math {
6767

6868
// Handle non-overflow cases, 256 by 256 division.
6969
if (prod1 == 0) {
70+
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
71+
// The surrounding unchecked block does not change this fact.
72+
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
7073
return prod0 / denominator;
7174
}
7275

docs/modules/ROOT/pages/erc4626.adoc

+22
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,25 @@ stem:[\delta = 3], stem:[a_0 = 100], stem:[a_1 = 10^5]
191191

192192
image::erc4626-attack-6.png[Inflation attack without offset=6]
193193
stem:[\delta = 6], stem:[a_0 = 1], stem:[a_1 = 10^5]
194+
195+
196+
[[fees]]
197+
== Custom behavior: Adding fees to the vault
198+
199+
In an ERC4626 vaults, fees can be captured during the deposit/mint and/or during the withdraw/redeem steps. In both cases it is essential to remain compliant with the ERC4626 requirements with regard to the preview functions.
200+
201+
For example, if calling `deposit(100, receiver)`, the caller should deposit exactly 100 underlying tokens, including fees, and the receiver should receive a number of shares that matches the value returned by `previewDeposit(100)`. Similarly, `previewMint` should account for the fees that the user will have to pay on top of share's cost.
202+
203+
As for the `Deposit` event, while this is less clear in the EIP spec itself, there seems to be consensus that it should include the number of assets paid for by the user, including the fees.
204+
205+
On the other hand, when withdrawing assets, the number given by the user should correspond to what he receives. Any fees should be added to the quote (in shares) performed by `previewWithdraw`.
206+
207+
The `Withdraw` event should include the number of shares the user burns (including fees) and the number of assets the user actually receives (after fees are deducted).
208+
209+
The consequence of this design is that both the `Deposit` and `Withdraw` events will describe two exchange rates. The spread between the "Buy-in" and the "Exit" prices correspond to the fees taken by the vault.
210+
211+
The following example describes how fees proportional to the deposited/withdrawn amount can be implemented:
212+
213+
```solidity
214+
include::api:example$ERC4626Fees.sol[]
215+
```

docs/modules/ROOT/pages/erc777.adoc

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
= ERC777
22

3+
CAUTION: As of v4.9, OpenZeppelin's implementation of ERC-777 is deprecated and will be removed in the next major release.
4+
35
Like xref:erc20.adoc[ERC20], ERC777 is a standard for xref:tokens.adoc#different-kinds-of-tokens[_fungible_ tokens], and is focused around allowing more complex interactions when trading tokens. More generally, it brings tokens and Ether closer together by providing the equivalent of a `msg.value` field, but for tokens.
46

57
The standard also brings multiple quality-of-life improvements, such as getting rid of the confusion around `decimals`, minting and burning with proper events, among others, but its killer feature is *receive hooks*. A hook is simply a function in a contract that is called when tokens are sent to it, meaning *accounts and contracts can react to receiving tokens*.

0 commit comments

Comments
 (0)