Compare commits
20 Commits
chore/remo
...
v4.8.2
| Author | SHA1 | Date | |
|---|---|---|---|
| d00acef405 | |||
| ab9cc4c4db | |||
| 43aa7ff1f5 | |||
| 167bf67ed3 | |||
| 82d47ca7b3 | |||
| 357022c1e8 | |||
| 9b610d3db4 | |||
| c018c9cf36 | |||
| d13316e8b1 | |||
| 3ab2e115a2 | |||
| 0457042d93 | |||
| 1dfccff485 | |||
| 472b996355 | |||
| cd50a86a90 | |||
| 873a01b220 | |||
| 011a0fb862 | |||
| 4e5b11919e | |||
| 3e97221049 | |||
| fad1172e63 | |||
| 53eb531255 |
5
.changeset/new-ways-own.md
Normal file
5
.changeset/new-ways-own.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'openzeppelin-solidity': patch
|
||||
---
|
||||
|
||||
`ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality
|
||||
2
.github/workflows/checks.yml
vendored
2
.github/workflows/checks.yml
vendored
@ -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'
|
||||
|
||||
3
.github/workflows/docs.yml
vendored
3
.github/workflows/docs.yml
vendored
@ -4,6 +4,9 @@ on:
|
||||
push:
|
||||
branches: [release-v*]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
24
CHANGELOG.md
24
CHANGELOG.md
@ -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
|
||||
|
||||
@ -12,6 +12,8 @@ This directory provides ways to restrict who can access the functions of a contr
|
||||
|
||||
{{Ownable}}
|
||||
|
||||
{{Ownable2Step}}
|
||||
|
||||
{{IAccessControl}}
|
||||
|
||||
{{AccessControl}}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
/**
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
/**
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 |
BIN
docs/modules/ROOT/images/tally-exec.png
Normal file
BIN
docs/modules/ROOT/images/tally-exec.png
Normal file
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 |
@ -19,3 +19,5 @@
|
||||
* xref:crosschain.adoc[Crosschain]
|
||||
|
||||
* xref:utilities.adoc[Utilities]
|
||||
|
||||
* xref:subgraphs::index.adoc[Subgraphs]
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
2
docs/templates/helpers.js
vendored
2
docs/templates/helpers.js
vendored
@ -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) => {
|
||||
|
||||
Submodule lib/forge-std updated: ca8d6e00ea...eb980e1d4f
4
package-lock.json
generated
4
package-lock.json
generated
@ -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"
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
}
|
||||
120
test/token/ERC721/extensions/ERC721Consecutive.t.sol
Normal file
120
test/token/ERC721/extensions/ERC721Consecutive.t.sol
Normal 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]);
|
||||
}
|
||||
}
|
||||
@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user