Skip to content

Commit

Permalink
Merge branch 'master' into lib-618-accesscontrol-admin-rules
Browse files Browse the repository at this point in the history
  • Loading branch information
frangio committed Feb 24, 2023
2 parents b2b9e81 + 2c6ef8c commit d1289a2
Show file tree
Hide file tree
Showing 18 changed files with 540 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .changeset/warm-masks-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

- `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))
- `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))
- `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))
- `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))

## 4.8.1 (2023-01-12)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
bytes[] memory calldatas,
string memory description
) public virtual override(IGovernor, Governor) returns (uint256) {
// Stores the proposal details (if not already present) and executes the propose logic from the core.
_storeProposal(_msgSender(), targets, values, new string[](calldatas.length), calldatas, description);
return super.propose(targets, values, calldatas, description);
}
Expand All @@ -69,6 +70,10 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
bytes[] memory calldatas,
string memory description
) public virtual override returns (uint256) {
// Stores the full proposal and fallback to the public (possibly overridden) propose. The fallback is done
// after the full proposal is stored, so the store operation included in the fallback will be skipped. Here we
// call `propose` and not `super.propose` to make sure if a child contract override `propose`, whatever code
// is added their is also executed when calling this alternative interface.
_storeProposal(_msgSender(), targets, values, signatures, calldatas, description);
return propose(targets, values, _encodeCalldata(signatures, calldatas), description);
}
Expand Down Expand Up @@ -174,7 +179,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
}

/**
* @dev Store proposal metadata for later lookup
* @dev Store proposal metadata (if not already present) for later lookup.
*/
function _storeProposal(
address proposer,
Expand Down
11 changes: 3 additions & 8 deletions contracts/interfaces/IERC1363.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,12 @@ import "./IERC165.sol";

interface IERC1363 is IERC165, IERC20 {
/*
* Note: the ERC-165 identifier for this interface is 0x4bbee2df.
* 0x4bbee2df ===
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)'))
*/

/*
* Note: the ERC-165 identifier for this interface is 0xfb9ec8ce.
* 0xfb9ec8ce ===
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
Expand Down
14 changes: 14 additions & 0 deletions contracts/interfaces/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ are useful to interact with third party contracts that implement them.
- {IERC1155MetadataURI}
- {IERC1271}
- {IERC1363}
- {IERC1363Receiver}
- {IERC1363Spender}
- {IERC1820Implementer}
- {IERC1820Registry}
- {IERC1822Proxiable}
Expand All @@ -30,7 +32,11 @@ are useful to interact with third party contracts that implement them.
- {IERC3156FlashLender}
- {IERC3156FlashBorrower}
- {IERC4626}
- {IERC4906}
- {IERC5267}
- {IERC5313}
- {IERC5805}
- {IERC6372}

== Detailed ABI

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

{{IERC1363Receiver}}

{{IERC1363Spender}}

{{IERC1820Implementer}}

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

{{IERC5313}}

{{IERC5267}}

{{IERC5805}}

{{IERC6372}}
87 changes: 87 additions & 0 deletions contracts/mocks/docs/ERC4626Fees.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../../token/ERC20/extensions/ERC4626.sol";

abstract contract ERC4626Fees is ERC4626 {
using Math for uint256;

/** @dev See {IERC4626-previewDeposit}. */
function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
uint256 fee = _feeOnTotal(assets, _entryFeeBasePoint());
return super.previewDeposit(assets - fee);
}

/** @dev See {IERC4626-previewMint}. */
function previewMint(uint256 shares) public view virtual override returns (uint256) {
uint256 assets = super.previewMint(shares);
return assets + _feeOnRaw(assets, _entryFeeBasePoint());
}

/** @dev See {IERC4626-previewWithdraw}. */
function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
uint256 fee = _feeOnRaw(assets, _exitFeeBasePoint());
return super.previewWithdraw(assets + fee);
}

/** @dev See {IERC4626-previewRedeem}. */
function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
uint256 assets = super.previewRedeem(shares);
return assets - _feeOnTotal(assets, _exitFeeBasePoint());
}

/** @dev See {IERC4626-_deposit}. */
function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override {
uint256 fee = _feeOnTotal(assets, _entryFeeBasePoint());
address recipient = _entryFeeRecipient();

super._deposit(caller, receiver, assets, shares);

if (fee > 0 && recipient != address(this)) {
SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
}
}

/** @dev See {IERC4626-_deposit}. */
function _withdraw(
address caller,
address receiver,
address owner,
uint256 assets,
uint256 shares
) internal virtual override {
uint256 fee = _feeOnRaw(assets, _exitFeeBasePoint());
address recipient = _exitFeeRecipient();

super._withdraw(caller, receiver, owner, assets, shares);

if (fee > 0 && recipient != address(this)) {
SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
}
}

function _entryFeeBasePoint() internal view virtual returns (uint256) {
return 0;
}

function _entryFeeRecipient() internal view virtual returns (address) {
return address(0);
}

function _exitFeeBasePoint() internal view virtual returns (uint256) {
return 0;
}

function _exitFeeRecipient() internal view virtual returns (address) {
return address(0);
}

function _feeOnRaw(uint256 assets, uint256 feeBasePoint) private pure returns (uint256) {
return assets.mulDiv(feeBasePoint, 1e5, Math.Rounding.Up);
}

function _feeOnTotal(uint256 assets, uint256 feeBasePoint) private pure returns (uint256) {
return assets.mulDiv(feeBasePoint, feeBasePoint + 1e5, Math.Rounding.Up);
}
}
40 changes: 40 additions & 0 deletions contracts/mocks/token/ERC4646FeesMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../docs/ERC4626Fees.sol";

abstract contract ERC4626FeesMock is ERC4626Fees {
uint256 private immutable _entryFeeBasePointValue;
address private immutable _entryFeeRecipientValue;
uint256 private immutable _exitFeeBasePointValue;
address private immutable _exitFeeRecipientValue;

constructor(
uint256 entryFeeBasePoint,
address entryFeeRecipient,
uint256 exitFeeBasePoint,
address exitFeeRecipient
) {
_entryFeeBasePointValue = entryFeeBasePoint;
_entryFeeRecipientValue = entryFeeRecipient;
_exitFeeBasePointValue = exitFeeBasePoint;
_exitFeeRecipientValue = exitFeeRecipient;
}

function _entryFeeBasePoint() internal view virtual override returns (uint256) {
return _entryFeeBasePointValue;
}

function _entryFeeRecipient() internal view virtual override returns (address) {
return _entryFeeRecipientValue;
}

function _exitFeeBasePoint() internal view virtual override returns (uint256) {
return _exitFeeBasePointValue;
}

function _exitFeeRecipient() internal view virtual override returns (address) {
return _exitFeeRecipientValue;
}
}
2 changes: 2 additions & 0 deletions contracts/token/ERC777/ERC777.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import "../../utils/introspection/IERC1820Registry.sol";
* Additionally, the {IERC777-granularity} value is hard-coded to `1`, meaning that there
* are no special restrictions in the amount of tokens that created, moved, or
* destroyed. This makes integration with ERC20 applications seamless.
*
* CAUTION: This file is deprecated as of v4.9 and will be removed in the next major release.
*/
contract ERC777 is Context, IERC777, IERC20 {
using Address for address;
Expand Down
2 changes: 2 additions & 0 deletions contracts/token/ERC777/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc777

CAUTION: As of v4.9, OpenZeppelin's implementation of ERC-777 is deprecated and will be removed in the next major release.

This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-777[ERC777 token standard].

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].
Expand Down
3 changes: 0 additions & 3 deletions contracts/utils/cryptography/EIP712.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ abstract contract EIP712 is IERC5267 {
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

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

/* solhint-enable var-name-mixedcase */

/**
* @dev Initializes the domain separator and parameter caches.
*
Expand Down
2 changes: 1 addition & 1 deletion contracts/utils/cryptography/SignatureChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ library SignatureChecker {
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
);
return (success &&
result.length == 32 &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}
2 changes: 2 additions & 0 deletions contracts/utils/introspection/ERC1820Implementer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import "./IERC1820Implementer.sol";
* declare their willingness to be implementers.
* {IERC1820Registry-setInterfaceImplementer} should then be called for the
* registration to be complete.
*
* CAUTION: This file is deprecated as of v4.9 and will be removed in the next major release.
*/
contract ERC1820Implementer is IERC1820Implementer {
bytes32 private constant _ERC1820_ACCEPT_MAGIC = keccak256("ERC1820_ACCEPT_MAGIC");
Expand Down
3 changes: 3 additions & 0 deletions contracts/utils/math/Math.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ library Math {

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

Expand Down
22 changes: 22 additions & 0 deletions docs/modules/ROOT/pages/erc4626.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,25 @@ stem:[\delta = 3], stem:[a_0 = 100], stem:[a_1 = 10^5]

image::erc4626-attack-6.png[Inflation attack without offset=6]
stem:[\delta = 6], stem:[a_0 = 1], stem:[a_1 = 10^5]


[[fees]]
== Custom behavior: Adding fees to the vault

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.

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.

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.

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`.

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).

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.

The following example describes how fees proportional to the deposited/withdrawn amount can be implemented:

```solidity
include::api:example$ERC4626Fees.sol[]
```
2 changes: 2 additions & 0 deletions docs/modules/ROOT/pages/erc777.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
= ERC777

CAUTION: As of v4.9, OpenZeppelin's implementation of ERC-777 is deprecated and will be removed in the next major release.

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.

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*.
Expand Down

0 comments on commit d1289a2

Please sign in to comment.