Compare commits

...

20 Commits

Author SHA1 Message Date
d00acef405 4.8.2 2023-03-02 20:03:13 -03:00
ab9cc4c4db Ignore reentrancy inexecuteBatch and update Slither config (#3955)
Co-authored-by: Francisco <fg@frang.io>
(cherry picked from commit a5af0adce4)
2023-03-02 19:56:45 -03:00
43aa7ff1f5 Update forge-std submodule to v1.2.0 (#3885)
Signed-off-by: Pascal Marco Caversaccio <pascal.caversaccio@hotmail.ch>
(cherry picked from commit 96ff934ad0)
2023-03-02 19:50:44 -03:00
167bf67ed3 Fix ERC721Consecutive balance update on batch size 1
Merge pull request from GHSA-878m-3g6q-594q

Co-authored-by: Francisco Giordano <fg@frang.io>
(cherry picked from commit 8ba26f388f)
2023-03-02 19:49:14 -03:00
82d47ca7b3 Add Subgraphs to docs sidebar
(cherry picked from commit 5e76b26225)
2023-02-16 14:34:36 -03:00
357022c1e8 Update Tally screenshots (#4030)
(cherry picked from commit 1575cc6908)
2023-02-06 12:21:19 -03:00
9b610d3db4 Add warning for supportsERC165InterfaceUnchecked edge case (#4017)
(cherry picked from commit d13ec90f37)
2023-02-03 16:18:39 -03:00
c018c9cf36 Remove outdated note about virtual view functions (#4014)
(cherry picked from commit 591c12d22d)
2023-01-30 21:01:24 -03:00
d13316e8b1 Add ERC*Pausable warning for public pausing mechanism (#4007)
Co-authored-by: Francisco <fg@frang.io>
(cherry picked from commit 1684c57922)
2023-01-30 21:01:22 -03:00
3ab2e115a2 Show if event parameter is indexed in docs (#3958)
Co-authored-by: Francisco <frangio.1@gmail.com>
(cherry picked from commit 18691d1a6f)
2023-01-16 16:06:08 -03:00
0457042d93 4.8.1 2023-01-13 15:34:06 -03:00
1dfccff485 Add docs on non-stability of internal function use (#3952)
(cherry picked from commit 717fbc45cb)
Signed-off-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2023-01-13 11:18:52 +01:00
472b996355 Add explicit permissions to docs workflow
(cherry picked from commit ac30219a6a)
2023-01-12 21:07:54 -03:00
cd50a86a90 Use a staticcall to fetch ERC20.decimals in ERC4626 (#3943)
Co-authored-by: Francisco <frangio.1@gmail.com>
(cherry picked from commit 6b17b33430)
Signed-off-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2023-01-12 17:13:13 +01:00
873a01b220 Fix governance tutorial contract (#3948)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
(cherry picked from commit 5dbde1a5c9)
2023-01-12 10:44:02 -03:00
011a0fb862 Add documentation about the security of overrides (#3725)
(cherry picked from commit e2362ce74f)
2023-01-10 12:41:57 -03:00
4e5b11919e Improve documentation of Initializable getters (#3861)
Co-authored-by: Ernesto García <ernestognw@gmail.com>
(cherry picked from commit 3d7a93876a)
2022-12-07 09:33:25 -05:00
3e97221049 Add ERC-4626 Upgrade Note (#3849)
(cherry picked from commit c30fad9955)
2022-12-02 17:11:02 -03:00
fad1172e63 Add Ownable2Step to the docs (#3836)
Co-authored-by: Francisco <fg@frang.io>
(cherry picked from commit 24d1bb668a)
2022-12-01 10:35:17 -03:00
53eb531255 Improve some NatSpec (#3809)
Co-authored-by: JulissaDantes <julissadcj@gmail.com>
(cherry picked from commit 8f8fd84f1e)
2022-11-25 13:11:43 -03:00
31 changed files with 273 additions and 67 deletions

View File

@ -0,0 +1,5 @@
---
'openzeppelin-solidity': patch
---
`ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality

View File

@ -76,7 +76,7 @@ jobs:
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- uses: crytic/slither-action@v0.1.1
- uses: crytic/slither-action@v0.2.0
codespell:
if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable'

View File

@ -4,6 +4,9 @@ on:
push:
branches: [release-v*]
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest

View File

@ -1,5 +1,17 @@
# Changelog
## 4.8.2 (2023-03-02)
- `ERC721Consecutive`: Fixed a bug when `_mintConsecutive` is used for batches of size 1 that could lead to balance overflow. Refer to the breaking changes section in the changelog for a note on the behavior of `ERC721._beforeTokenTransfer`.
### Breaking changes
- `ERC721`: The internal function `_beforeTokenTransfer` no longer updates balances, which it previously did when `batchSize` was greater than 1. This change has no consequence unless a custom ERC721 extension is explicitly invoking `_beforeTokenTransfer`. Balance updates in extensions must now be done explicitly using `__unsafe_increaseBalance`, with a name that indicates that there is an invariant that has to be manually verified.
## 4.8.1 (2023-01-13)
* `ERC4626`: Use staticcall instead of call when fetching underlying ERC-20 decimals. ([#3943](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3943))
## 4.8.0 (2022-11-08)
* `TimelockController`: Added a new `admin` constructor parameter that is assigned the admin role instead of the deployer account. ([#3722](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3722))
@ -75,6 +87,18 @@ ERC-721 integrators that interpret contract state from events should make sure t
With the new `ERC721Consecutive` extension, the internal workings of `ERC721` are slightly changed. Custom extensions to ERC721 should be reviewed to ensure they remain correct. The internal functions that should be considered are `_ownerOf` (new), `_beforeTokenTransfer`, and `_afterTokenTransfer`.
### ERC-4626 Upgrade Note
Existing `ERC4626` contracts that are upgraded to 4.8 must initialize a new variable that holds the vault token decimals. The recommended way to do this is to use a [reinitializer]:
[reinitializer]: https://docs.openzeppelin.com/contracts/4.x/api/proxy#Initializable-reinitializer-uint8-
```solidity
function migrateToV48() public reinitializer(2) {
__ERC4626_init(IERC20Upgradeable(asset()));
}
```
## 4.7.3
### Breaking changes

View File

@ -12,6 +12,8 @@ This directory provides ways to restrict who can access the functions of a contr
{{Ownable}}
{{Ownable2Step}}
{{IAccessControl}}
{{AccessControl}}

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (governance/TimelockController.sol)
// OpenZeppelin Contracts (last updated v4.8.2) (governance/TimelockController.sol)
pragma solidity ^0.8.0;
@ -316,6 +316,9 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver
*
* - the caller must have the 'executor' role.
*/
// This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending,
// thus any modifications to the operation during reentrancy should be caught.
// slither-disable-next-line reentrancy-eth
function executeBatch(
address[] calldata targets,
uint256[] calldata values,

View File

@ -1,7 +1,7 @@
{
"name": "@openzeppelin/contracts",
"description": "Secure Smart Contract library for Solidity",
"version": "4.8.0",
"version": "4.8.2",
"files": [
"**/*.sol",
"/build/contracts/*.json",

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
@ -150,14 +150,14 @@ abstract contract Initializable {
}
/**
* @dev Internal function that returns the initialized version. Returns `_initialized`
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Internal function that returns the initialized version. Returns `_initializing`
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/ERC1155Pausable.sol)
// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC1155/extensions/ERC1155Pausable.sol)
pragma solidity ^0.8.0;
@ -13,6 +13,12 @@ import "../../../security/Pausable.sol";
* period, or having an emergency switch for freezing all token transfers in the
* event of a large bug.
*
* IMPORTANT: This contract does not include public pause and unpause functions. In
* addition to inheriting this contract, you must define both functions, invoking the
* {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
* access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
* make the contract unpausable.
*
* _Available since v3.1._
*/
abstract contract ERC1155Pausable is ERC1155, Pausable {

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Pausable.sol)
// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC20/extensions/ERC20Pausable.sol)
pragma solidity ^0.8.0;
@ -12,6 +12,12 @@ import "../../../security/Pausable.sol";
* Useful for scenarios such as preventing trades until the end of an evaluation
* period, or having an emergency switch for freezing all token transfers in the
* event of a large bug.
*
* IMPORTANT: This contract does not include public pause and unpause functions. In
* addition to inheriting this contract, you must define both functions, invoking the
* {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
* access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
* make the contract unpausable.
*/
abstract contract ERC20Pausable is ERC20, Pausable {
/**

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20Votes.sol)
// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC20Votes.sol)
pragma solidity ^0.8.0;
@ -263,6 +263,9 @@ abstract contract ERC20Votes is IVotes, ERC20Permit {
return a - b;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
assembly {
mstore(0, ckpts.slot)

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC4626.sol)
// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC4626.sol)
pragma solidity ^0.8.0;
@ -17,8 +17,12 @@ import "../../../utils/math/Math.sol";
* the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
* contract and not the "assets" token which is an independent contract.
*
* CAUTION: Deposits and withdrawals may incur unexpected slippage. Users should verify that the amount received of
* shares or assets is as expected. EOAs should operate through a wrapper that performs these checks such as
* CAUTION: When the vault is empty or nearly empty, deposits are at high risk of being stolen through frontrunning with
* a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation
* attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial
* deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may
* similarly be affected by slippage. Users can protect against this attack as well unexpected slippage in general by
* verifying the amount received is as expected, using a wrapper that performs these checks such as
* https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
*
* _Available since v4.7._
@ -41,8 +45,8 @@ abstract contract ERC4626 is ERC20, IERC4626 {
/**
* @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.
*/
function _tryGetAssetDecimals(IERC20 asset_) private returns (bool, uint8) {
(bool success, bytes memory encodedDecimals) = address(asset_).call(
function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool, uint8) {
(bool success, bytes memory encodedDecimals) = address(asset_).staticcall(
abi.encodeWithSelector(IERC20Metadata.decimals.selector)
);
if (success && encodedDecimals.length >= 32) {
@ -134,7 +138,11 @@ abstract contract ERC4626 is ERC20, IERC4626 {
return shares;
}
/** @dev See {IERC4626-mint}. */
/** @dev See {IERC4626-mint}.
*
* As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero.
* In this case, the shares will be minted without requiring any assets to be deposited.
*/
function mint(uint256 shares, address receiver) public virtual override returns (uint256) {
require(shares <= maxMint(receiver), "ERC4626: mint more than max");
@ -267,6 +275,9 @@ abstract contract ERC4626 is ERC20, IERC4626 {
emit Withdraw(caller, receiver, owner, assets, shares);
}
/**
* @dev Checks if vault is "healthy" in the sense of having assets backing the circulating shares.
*/
function _isVaultCollateralized() private view returns (bool) {
return totalAssets() > 0 || totalSupply() == 0;
}

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)
// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.0;
@ -467,18 +467,9 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
function _beforeTokenTransfer(
address from,
address to,
uint256, /* firstTokenId */
uint256 firstTokenId,
uint256 batchSize
) internal virtual {
if (batchSize > 1) {
if (from != address(0)) {
_balances[from] -= batchSize;
}
if (to != address(0)) {
_balances[to] += batchSize;
}
}
}
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
@ -500,4 +491,16 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
uint256 firstTokenId,
uint256 batchSize
) internal virtual {}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant
* being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such
* that `ownerOf(tokenId)` is `a`.
*/
// solhint-disable-next-line func-name-mixedcase
function __unsafe_increaseBalance(address account, uint256 amount) internal {
_balances[account] += amount;
}
}

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Consecutive.sol)
// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/extensions/ERC721Consecutive.sol)
pragma solidity ^0.8.0;
@ -96,6 +96,11 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
// push an ownership checkpoint & emit event
uint96 last = first + batchSize - 1;
_sequentialOwnership.push(last, uint160(to));
// The invariant required by this function is preserved because the new sequentialOwnership checkpoint
// is attributing ownership of `batchSize` new tokens to account `to`.
__unsafe_increaseBalance(to, batchSize);
emit ConsecutiveTransfer(first, last, address(0), to);
// hook after

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Pausable.sol)
// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/extensions/ERC721Pausable.sol)
pragma solidity ^0.8.0;
@ -12,6 +12,12 @@ import "../../../security/Pausable.sol";
* Useful for scenarios such as preventing trades until the end of an evaluation
* period, or having an emergency switch for freezing all token transfers in the
* event of a large bug.
*
* IMPORTANT: This contract does not include public pause and unpause functions. In
* addition to inheriting this contract, you must define both functions, invoking the
* {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
* access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
* make the contract unpausable.
*/
abstract contract ERC721Pausable is ERC721, Pausable {
/**

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Checkpoints.sol)
// OpenZeppelin Contracts (last updated v4.8.1) (utils/Checkpoints.sol)
// This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
pragma solidity ^0.8.0;
@ -28,7 +28,8 @@ library Checkpoints {
/**
* @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
* before it is returned, or zero otherwise.
* before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the
* block, the requested block number must be in the past, excluding the current block.
*/
function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {
require(blockNumber < block.number, "Checkpoints: block not yet mined");
@ -205,6 +206,9 @@ library Checkpoints {
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) {
assembly {
mstore(0, self.slot)
@ -366,6 +370,9 @@ library Checkpoints {
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(Checkpoint224[] storage self, uint256 pos)
private
pure
@ -531,6 +538,9 @@ library Checkpoints {
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(Checkpoint160[] storage self, uint256 pos)
private
pure

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/ERC165Checker.sol)
// OpenZeppelin Contracts (last updated v4.8.2) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.0;
@ -102,6 +102,10 @@ library ERC165Checker {
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -19,3 +19,5 @@
* xref:crosschain.adoc[Crosschain]
* xref:utilities.adoc[Utilities]
* xref:subgraphs::index.adoc[Subgraphs]

View File

@ -66,8 +66,6 @@ contract ModifiedAccessControl is AccessControl {
The `super.revokeRole` statement at the end will invoke ``AccessControl``'s original version of `revokeRole`, the same code that would've run if there were no overrides in place.
NOTE: As of v3.0.0, `view` functions are not `virtual` in OpenZeppelin, and therefore cannot be overridden. We're considering https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2154[lifting this restriction] in an upcoming release. Let us know if this is something you care about!
[[using-hooks]]
== Using Hooks
@ -122,3 +120,10 @@ contract MyToken is ERC20 {
```
That's it! Enjoy simpler code using hooks!
== Security
The maintainers of OpenZeppelin Contracts are mainly concerned with the correctness and security of the code as published in the library, and the combinations of base contracts with the official extensions from the library.
Custom overrides, and those of hooks in particular, may break some important assumptions and introduce vulnerabilities in otherwise secure code. While we try to ensure the contracts remain secure in the face of a wide range of potential customizations, this is done in a best-effort manner. While we try to document all important assumptions, this should not be relied upon. Custom overrides should be carefully reviewed and checked against the source code of the contract they are customizing so as to fully understand their impact and guarantee their security.
The way functions interact internally should not be assumed to stay stable across releases of the library. For example, a function that is used in one context in a particular release may not be used in the same context in the next release. Contracts that override functions should revalidate their assumptions when updating the version of OpenZeppelin Contracts they are built on.

View File

@ -145,11 +145,11 @@ We can optionally set a proposal threshold as well. This restricts proposal crea
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "./governance/Governor.sol";
import "./governance/compatibility/GovernorCompatibilityBravo.sol";
import "./governance/extensions/GovernorVotes.sol";
import "./governance/extensions/GovernorVotesQuorumFraction.sol";
import "./governance/extensions/GovernorTimelockControl.sol";
import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/compatibility/GovernorCompatibilityBravo.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
contract MyGovernor is Governor, GovernorCompatibilityBravo, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl {
constructor(IVotes _token, TimelockController _timelock)
@ -173,24 +173,6 @@ contract MyGovernor is Governor, GovernorCompatibilityBravo, GovernorVotes, Gove
// The functions below are overrides required by Solidity.
function quorum(uint256 blockNumber)
public
view
override(IGovernor, GovernorVotesQuorumFraction)
returns (uint256)
{
return super.quorum(blockNumber);
}
function getVotes(address account, uint256 blockNumber)
public
view
override(IGovernor, GovernorVotes)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
function state(uint256 proposalId)
public
view
@ -302,9 +284,9 @@ image::tally-vote.png[Voting in Tally]
=== Execute the Proposal
Once the voting period is over, if quorum was reached (enough voting power participated) and the majority voted in favor, the proposal is considered successful and can proceed to be executed. This can also be done in Tally in the "Administration Panel" section of a project.
Once the voting period is over, if quorum was reached (enough voting power participated) and the majority voted in favor, the proposal is considered successful and can proceed to be executed. Once a proposal passes, it can be queued and executed from the same place you voted.
image::tally-admin.png[Administration Panel in Tally]
image::tally-exec.png[Administration Panel in Tally]
We will see now how to do this manually using Ethers.js.

View File

@ -9,7 +9,7 @@ module.exports['readme-path'] = (opts) => {
module.exports.names = (params) => params.map(p => p.name).join(', ');
module.exports['typed-params'] = (params) => {
return params.map(p => `${p.type}${p.name ? ' ' + p.name : ''}`).join(', ');
return params?.map(p => `${p.type}${p.indexed ? ' indexed' : ''}${p.name ? ' ' + p.name : ''}`).join(', ');
};
const slug = module.exports.slug = (str) => {

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "openzeppelin-solidity",
"version": "4.8.0",
"version": "4.8.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "openzeppelin-solidity",
"version": "4.8.0",
"version": "4.8.2",
"license": "MIT",
"bin": {
"openzeppelin-contracts-migrate-imports": "scripts/migrate-imports.js"

View File

@ -1,7 +1,7 @@
{
"name": "openzeppelin-solidity",
"description": "Secure Smart Contract library for Solidity",
"version": "4.8.0",
"version": "4.8.2",
"files": [
"/contracts/**/*.sol",
"/build/contracts/*.json",

View File

@ -67,7 +67,8 @@ function upperLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} k
const legacyOperations = opts => `\
/**
* @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one
* before it is returned, or zero otherwise.
* before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the
* block, the requested block number must be in the past, excluding the current block.
*/
function getAtBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) {
require(blockNumber < block.number, "Checkpoints: block not yet mined");
@ -246,6 +247,9 @@ function _lowerBinaryLookup(
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos)
private
pure

View File

@ -1,4 +1,5 @@
{
"detectors_to_run": "reentrancy-eth,reentrancy-no-eth,reentrancy-unlimited-gas",
"filter_paths": "contracts/mocks"
"filter_paths": "contracts/mocks",
"compile_force_framework": "hardhat"
}

View File

@ -0,0 +1,120 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../../../../contracts/token/ERC721/extensions/ERC721Consecutive.sol";
import "forge-std/Test.sol";
function toSingleton(address account) pure returns (address[] memory) {
address[] memory accounts = new address[](1);
accounts[0] = account;
return accounts;
}
contract ERC721ConsecutiveTarget is StdUtils, ERC721Consecutive {
uint256 public totalMinted = 0;
constructor(address[] memory receivers, uint256[] memory batches) ERC721("", "") {
for (uint256 i = 0; i < batches.length; i++) {
address receiver = receivers[i % receivers.length];
uint96 batchSize = uint96(bound(batches[i], 0, _maxBatchSize()));
_mintConsecutive(receiver, batchSize);
totalMinted += batchSize;
}
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}
contract ERC721ConsecutiveTest is Test {
function test_balance(address receiver, uint256[] calldata batches) public {
vm.assume(receiver != address(0));
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches);
assertEq(token.balanceOf(receiver), token.totalMinted());
}
function test_ownership(address receiver, uint256[] calldata batches, uint256[2] calldata unboundedTokenId) public {
vm.assume(receiver != address(0));
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches);
if (token.totalMinted() > 0) {
uint256 validTokenId = bound(unboundedTokenId[0], 0, token.totalMinted() - 1);
assertEq(token.ownerOf(validTokenId), receiver);
}
uint256 invalidTokenId = bound(unboundedTokenId[1], token.totalMinted(), type(uint256).max);
vm.expectRevert();
token.ownerOf(invalidTokenId);
}
function test_burn(address receiver, uint256[] calldata batches, uint256 unboundedTokenId) public {
vm.assume(receiver != address(0));
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches);
// only test if we minted at least one token
uint256 supply = token.totalMinted();
vm.assume(supply > 0);
// burn a token in [0; supply[
uint256 tokenId = bound(unboundedTokenId, 0, supply - 1);
token.burn(tokenId);
// balance should have decreased
assertEq(token.balanceOf(receiver), supply - 1);
// token should be burnt
vm.expectRevert();
token.ownerOf(tokenId);
}
function test_transfer(
address[2] calldata accounts,
uint256[2] calldata unboundedBatches,
uint256[2] calldata unboundedTokenId
) public {
vm.assume(accounts[0] != address(0));
vm.assume(accounts[1] != address(0));
vm.assume(accounts[0] != accounts[1]);
address[] memory receivers = new address[](2);
receivers[0] = accounts[0];
receivers[1] = accounts[1];
// We assume _maxBatchSize is 5000 (the default). This test will break otherwise.
uint256[] memory batches = new uint256[](2);
batches[0] = bound(unboundedBatches[0], 1, 5000);
batches[1] = bound(unboundedBatches[1], 1, 5000);
ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(receivers, batches);
uint256 tokenId0 = bound(unboundedTokenId[0], 0, batches[0] - 1);
uint256 tokenId1 = bound(unboundedTokenId[1], 0, batches[1] - 1) + batches[0];
assertEq(token.ownerOf(tokenId0), accounts[0]);
assertEq(token.ownerOf(tokenId1), accounts[1]);
assertEq(token.balanceOf(accounts[0]), batches[0]);
assertEq(token.balanceOf(accounts[1]), batches[1]);
vm.prank(accounts[0]);
token.transferFrom(accounts[0], accounts[1], tokenId0);
assertEq(token.ownerOf(tokenId0), accounts[1]);
assertEq(token.ownerOf(tokenId1), accounts[1]);
assertEq(token.balanceOf(accounts[0]), batches[0] - 1);
assertEq(token.balanceOf(accounts[1]), batches[1] + 1);
vm.prank(accounts[1]);
token.transferFrom(accounts[1], accounts[0], tokenId1);
assertEq(token.ownerOf(tokenId0), accounts[1]);
assertEq(token.ownerOf(tokenId1), accounts[0]);
assertEq(token.balanceOf(accounts[0]), batches[0]);
assertEq(token.balanceOf(accounts[1]), batches[1]);
}
}

View File

@ -12,7 +12,8 @@ contract('ERC721Consecutive', function (accounts) {
const symbol = 'NFT';
const batches = [
{ receiver: user1, amount: 0 },
{ receiver: user1, amount: 3 },
{ receiver: user1, amount: 1 },
{ receiver: user1, amount: 2 },
{ receiver: user2, amount: 5 },
{ receiver: user3, amount: 0 },
{ receiver: user1, amount: 7 },