Compare commits
28 Commits
frangio-pa
...
release-v4
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a25c1940c | |||
| 7bdd255a05 | |||
| ea595f5960 | |||
| 61b45a2850 | |||
| db9ee953a1 | |||
| c01ea99123 | |||
| 8dfeb5d79e | |||
| 9eee01c5a2 | |||
| 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
|
||||
|
||||
1
.gitmodules
vendored
1
.gitmodules
vendored
@ -1,3 +1,4 @@
|
||||
[submodule "lib/forge-std"]
|
||||
branch = v1
|
||||
path = lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
|
||||
29
CHANGELOG.md
29
CHANGELOG.md
@ -1,5 +1,22 @@
|
||||
# Changelog
|
||||
|
||||
## 4.8.3 (2023-04-13)
|
||||
|
||||
- `GovernorCompatibilityBravo`: Fix encoding of proposal data when signatures are missing.
|
||||
- `TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata or payable mutability. ([#4154](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4154))
|
||||
|
||||
## 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 +92,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,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v4.8.0) (governance/compatibility/GovernorCompatibilityBravo.sol)
|
||||
// OpenZeppelin Contracts (last updated v4.8.3) (governance/compatibility/GovernorCompatibilityBravo.sol)
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
@ -69,6 +69,11 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
|
||||
bytes[] memory calldatas,
|
||||
string memory description
|
||||
) public virtual override returns (uint256) {
|
||||
require(signatures.length == calldatas.length, "GovernorBravo: invalid signatures length");
|
||||
// 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);
|
||||
}
|
||||
@ -124,8 +129,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp
|
||||
returns (bytes[] memory)
|
||||
{
|
||||
bytes[] memory fullcalldatas = new bytes[](calldatas.length);
|
||||
|
||||
for (uint256 i = 0; i < signatures.length; ++i) {
|
||||
for (uint256 i = 0; i < fullcalldatas.length; ++i) {
|
||||
fullcalldatas[i] = bytes(signatures[i]).length == 0
|
||||
? calldatas[i]
|
||||
: abi.encodePacked(bytes4(keccak256(bytes(signatures[i]))), calldatas[i]);
|
||||
|
||||
26
contracts/interfaces/IERC1967.sol
Normal file
26
contracts/interfaces/IERC1967.sol
Normal file
@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol)
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
/**
|
||||
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
|
||||
*
|
||||
* _Available since v4.9._
|
||||
*/
|
||||
interface IERC1967 {
|
||||
/**
|
||||
* @dev Emitted when the implementation is upgraded.
|
||||
*/
|
||||
event Upgraded(address indexed implementation);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the admin account has changed.
|
||||
*/
|
||||
event AdminChanged(address previousAdmin, address newAdmin);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the beacon is changed.
|
||||
*/
|
||||
event BeaconUpgraded(address indexed beacon);
|
||||
}
|
||||
@ -3,12 +3,11 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
/**
|
||||
* @dev Implementation contract with an admin() function made to clash with
|
||||
* @dev TransparentUpgradeableProxy's to test correct functioning of the
|
||||
* @dev Transparent Proxy feature.
|
||||
* @dev Implementation contract with a payable admin() function made to clash with TransparentUpgradeableProxy's to
|
||||
* test correct functioning of the Transparent Proxy feature.
|
||||
*/
|
||||
contract ClashingImplementation {
|
||||
function admin() external pure returns (address) {
|
||||
function admin() external payable returns (address) {
|
||||
return 0x0000000000000000000000000000000011111142;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@openzeppelin/contracts",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"version": "4.8.0",
|
||||
"version": "4.8.3",
|
||||
"files": [
|
||||
"**/*.sol",
|
||||
"/build/contracts/*.json",
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
|
||||
// OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol)
|
||||
|
||||
pragma solidity ^0.8.2;
|
||||
|
||||
import "../beacon/IBeacon.sol";
|
||||
import "../../interfaces/IERC1967.sol";
|
||||
import "../../interfaces/draft-IERC1822.sol";
|
||||
import "../../utils/Address.sol";
|
||||
import "../../utils/StorageSlot.sol";
|
||||
@ -16,7 +17,7 @@ import "../../utils/StorageSlot.sol";
|
||||
*
|
||||
* @custom:oz-upgrades-unsafe-allow delegatecall
|
||||
*/
|
||||
abstract contract ERC1967Upgrade {
|
||||
abstract contract ERC1967Upgrade is IERC1967 {
|
||||
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
|
||||
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
|
||||
|
||||
@ -27,11 +28,6 @@ abstract contract ERC1967Upgrade {
|
||||
*/
|
||||
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
|
||||
|
||||
/**
|
||||
* @dev Emitted when the implementation is upgraded.
|
||||
*/
|
||||
event Upgraded(address indexed implementation);
|
||||
|
||||
/**
|
||||
* @dev Returns the current implementation address.
|
||||
*/
|
||||
@ -105,11 +101,6 @@ abstract contract ERC1967Upgrade {
|
||||
*/
|
||||
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
|
||||
|
||||
/**
|
||||
* @dev Emitted when the admin account has changed.
|
||||
*/
|
||||
event AdminChanged(address previousAdmin, address newAdmin);
|
||||
|
||||
/**
|
||||
* @dev Returns the current admin.
|
||||
*/
|
||||
@ -141,11 +132,6 @@ abstract contract ERC1967Upgrade {
|
||||
*/
|
||||
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
|
||||
|
||||
/**
|
||||
* @dev Emitted when the beacon is upgraded.
|
||||
*/
|
||||
event BeaconUpgraded(address indexed beacon);
|
||||
|
||||
/**
|
||||
* @dev Returns the current beacon.
|
||||
*/
|
||||
|
||||
@ -56,6 +56,8 @@ The current implementation of this security mechanism uses https://eips.ethereum
|
||||
|
||||
== ERC1967
|
||||
|
||||
{{IERC1967}}
|
||||
|
||||
{{ERC1967Proxy}}
|
||||
|
||||
{{ERC1967Upgrade}}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol)
|
||||
// OpenZeppelin Contracts (last updated v4.8.3) (proxy/transparent/ProxyAdmin.sol)
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
@ -18,7 +18,7 @@ contract ProxyAdmin is Ownable {
|
||||
*
|
||||
* - This contract must be the admin of `proxy`.
|
||||
*/
|
||||
function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
|
||||
function getProxyImplementation(ITransparentUpgradeableProxy proxy) public view virtual returns (address) {
|
||||
// We need to manually run the static call since the getter cannot be flagged as view
|
||||
// bytes4(keccak256("implementation()")) == 0x5c60da1b
|
||||
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
|
||||
@ -33,7 +33,7 @@ contract ProxyAdmin is Ownable {
|
||||
*
|
||||
* - This contract must be the admin of `proxy`.
|
||||
*/
|
||||
function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
|
||||
function getProxyAdmin(ITransparentUpgradeableProxy proxy) public view virtual returns (address) {
|
||||
// We need to manually run the static call since the getter cannot be flagged as view
|
||||
// bytes4(keccak256("admin()")) == 0xf851a440
|
||||
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
|
||||
@ -48,7 +48,7 @@ contract ProxyAdmin is Ownable {
|
||||
*
|
||||
* - This contract must be the current admin of `proxy`.
|
||||
*/
|
||||
function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
|
||||
function changeProxyAdmin(ITransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
|
||||
proxy.changeAdmin(newAdmin);
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ contract ProxyAdmin is Ownable {
|
||||
*
|
||||
* - This contract must be the admin of `proxy`.
|
||||
*/
|
||||
function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
|
||||
function upgrade(ITransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
|
||||
proxy.upgradeTo(implementation);
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ contract ProxyAdmin is Ownable {
|
||||
* - This contract must be the admin of `proxy`.
|
||||
*/
|
||||
function upgradeAndCall(
|
||||
TransparentUpgradeableProxy proxy,
|
||||
ITransparentUpgradeableProxy proxy,
|
||||
address implementation,
|
||||
bytes memory data
|
||||
) public payable virtual onlyOwner {
|
||||
|
||||
@ -1,10 +1,28 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
|
||||
// OpenZeppelin Contracts (last updated v4.8.3) (proxy/transparent/TransparentUpgradeableProxy.sol)
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../ERC1967/ERC1967Proxy.sol";
|
||||
|
||||
/**
|
||||
* @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
|
||||
* does not implement this interface directly, and some of its functions are implemented by an internal dispatch
|
||||
* mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
|
||||
* include them in the ABI so this interface must be used to interact with it.
|
||||
*/
|
||||
interface ITransparentUpgradeableProxy is IERC1967 {
|
||||
function admin() external view returns (address);
|
||||
|
||||
function implementation() external view returns (address);
|
||||
|
||||
function changeAdmin(address) external;
|
||||
|
||||
function upgradeTo(address) external;
|
||||
|
||||
function upgradeToAndCall(address, bytes memory) external payable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev This contract implements a proxy that is upgradeable by an admin.
|
||||
*
|
||||
@ -25,6 +43,17 @@ import "../ERC1967/ERC1967Proxy.sol";
|
||||
*
|
||||
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
|
||||
* you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
|
||||
*
|
||||
* NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
|
||||
* inherit from that interface, and instead the admin functions are implicitly implemented using a custom dispatch
|
||||
* mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
|
||||
* fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
|
||||
* implementation.
|
||||
*
|
||||
* WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the compiler
|
||||
* will not check that there are no selector conflicts, due to the note above. A selector clash between any new function
|
||||
* and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could
|
||||
* render the admin operations inaccessible, which could prevent upgradeability. Transparency may also be compromised.
|
||||
*/
|
||||
contract TransparentUpgradeableProxy is ERC1967Proxy {
|
||||
/**
|
||||
@ -41,6 +70,9 @@ contract TransparentUpgradeableProxy is ERC1967Proxy {
|
||||
|
||||
/**
|
||||
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
|
||||
*
|
||||
* CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the
|
||||
* implementation provides a function with the same selector.
|
||||
*/
|
||||
modifier ifAdmin() {
|
||||
if (msg.sender == _getAdmin()) {
|
||||
@ -50,61 +82,98 @@ contract TransparentUpgradeableProxy is ERC1967Proxy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior
|
||||
*/
|
||||
function _fallback() internal virtual override {
|
||||
if (msg.sender == _getAdmin()) {
|
||||
bytes memory ret;
|
||||
bytes4 selector = msg.sig;
|
||||
if (selector == ITransparentUpgradeableProxy.upgradeTo.selector) {
|
||||
ret = _dispatchUpgradeTo();
|
||||
} else if (selector == ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
|
||||
ret = _dispatchUpgradeToAndCall();
|
||||
} else if (selector == ITransparentUpgradeableProxy.changeAdmin.selector) {
|
||||
ret = _dispatchChangeAdmin();
|
||||
} else if (selector == ITransparentUpgradeableProxy.admin.selector) {
|
||||
ret = _dispatchAdmin();
|
||||
} else if (selector == ITransparentUpgradeableProxy.implementation.selector) {
|
||||
ret = _dispatchImplementation();
|
||||
} else {
|
||||
revert("TransparentUpgradeableProxy: admin cannot fallback to proxy target");
|
||||
}
|
||||
assembly {
|
||||
return(add(ret, 0x20), mload(ret))
|
||||
}
|
||||
} else {
|
||||
super._fallback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the current admin.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
|
||||
*
|
||||
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
|
||||
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
|
||||
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
|
||||
*/
|
||||
function admin() external ifAdmin returns (address admin_) {
|
||||
admin_ = _getAdmin();
|
||||
function _dispatchAdmin() private returns (bytes memory) {
|
||||
_requireZeroValue();
|
||||
|
||||
address admin = _getAdmin();
|
||||
return abi.encode(admin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the current implementation.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
|
||||
*
|
||||
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
|
||||
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
|
||||
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
|
||||
*/
|
||||
function implementation() external ifAdmin returns (address implementation_) {
|
||||
implementation_ = _implementation();
|
||||
function _dispatchImplementation() private returns (bytes memory) {
|
||||
_requireZeroValue();
|
||||
|
||||
address implementation = _implementation();
|
||||
return abi.encode(implementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Changes the admin of the proxy.
|
||||
*
|
||||
* Emits an {AdminChanged} event.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
|
||||
*/
|
||||
function changeAdmin(address newAdmin) external virtual ifAdmin {
|
||||
function _dispatchChangeAdmin() private returns (bytes memory) {
|
||||
_requireZeroValue();
|
||||
|
||||
address newAdmin = abi.decode(msg.data[4:], (address));
|
||||
_changeAdmin(newAdmin);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrade the implementation of the proxy.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
|
||||
*/
|
||||
function upgradeTo(address newImplementation) external ifAdmin {
|
||||
function _dispatchUpgradeTo() private returns (bytes memory) {
|
||||
_requireZeroValue();
|
||||
|
||||
address newImplementation = abi.decode(msg.data[4:], (address));
|
||||
_upgradeToAndCall(newImplementation, bytes(""), false);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
|
||||
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
|
||||
* proxied contract.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
|
||||
*/
|
||||
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
|
||||
function _dispatchUpgradeToAndCall() private returns (bytes memory) {
|
||||
(address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
|
||||
_upgradeToAndCall(newImplementation, data, true);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,10 +184,10 @@ contract TransparentUpgradeableProxy is ERC1967Proxy {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
|
||||
* @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to
|
||||
* emulate some proxy functions being non-payable while still allowing value to pass through.
|
||||
*/
|
||||
function _beforeFallback() internal virtual override {
|
||||
require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
|
||||
super._beforeFallback();
|
||||
function _requireZeroValue() private {
|
||||
require(msg.value == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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...c2236853aa
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "openzeppelin-solidity",
|
||||
"version": "4.8.0",
|
||||
"version": "4.8.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "openzeppelin-solidity",
|
||||
"version": "4.8.0",
|
||||
"version": "4.8.3",
|
||||
"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.3",
|
||||
"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"
|
||||
}
|
||||
@ -223,6 +223,21 @@ contract('GovernorCompatibilityBravo', function (accounts) {
|
||||
);
|
||||
});
|
||||
|
||||
it('with inconsistent array size for selector and arguments', async function () {
|
||||
const target = this.receiver.address;
|
||||
this.helper.setProposal(
|
||||
{
|
||||
targets: [target, target],
|
||||
values: [0, 0],
|
||||
signatures: ['mockFunction()'], // One signature
|
||||
data: ['0x', this.receiver.contract.methods.mockFunctionWithArgs(17, 42).encodeABI()], // Two data entries
|
||||
},
|
||||
'<proposal description>',
|
||||
);
|
||||
|
||||
await expectRevert(this.helper.propose({ from: proposer }), 'GovernorBravo: invalid signatures length');
|
||||
});
|
||||
|
||||
describe('should revert', function () {
|
||||
describe('on propose', function () {
|
||||
it('if proposal does not meet proposalThreshold', async function () {
|
||||
|
||||
@ -6,6 +6,7 @@ const ImplV1 = artifacts.require('DummyImplementation');
|
||||
const ImplV2 = artifacts.require('DummyImplementationV2');
|
||||
const ProxyAdmin = artifacts.require('ProxyAdmin');
|
||||
const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy');
|
||||
const ITransparentUpgradeableProxy = artifacts.require('ITransparentUpgradeableProxy');
|
||||
|
||||
contract('ProxyAdmin', function (accounts) {
|
||||
const [proxyAdminOwner, newAdmin, anotherAccount] = accounts;
|
||||
@ -18,12 +19,13 @@ contract('ProxyAdmin', function (accounts) {
|
||||
beforeEach(async function () {
|
||||
const initializeData = Buffer.from('');
|
||||
this.proxyAdmin = await ProxyAdmin.new({ from: proxyAdminOwner });
|
||||
this.proxy = await TransparentUpgradeableProxy.new(
|
||||
const proxy = await TransparentUpgradeableProxy.new(
|
||||
this.implementationV1.address,
|
||||
this.proxyAdmin.address,
|
||||
initializeData,
|
||||
{ from: proxyAdminOwner },
|
||||
);
|
||||
this.proxy = await ITransparentUpgradeableProxy.at(proxy.address);
|
||||
});
|
||||
|
||||
it('has an owner', async function () {
|
||||
|
||||
@ -34,7 +34,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
|
||||
|
||||
describe('implementation', function () {
|
||||
it('returns the current implementation address', async function () {
|
||||
const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress });
|
||||
const implementation = await this.proxy.implementation({ from: proxyAdminAddress });
|
||||
|
||||
expect(implementation).to.be.equal(this.implementationV0);
|
||||
});
|
||||
@ -55,7 +55,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
|
||||
it('upgrades to the requested implementation', async function () {
|
||||
await this.proxy.upgradeTo(this.implementationV1, { from });
|
||||
|
||||
const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress });
|
||||
const implementation = await this.proxy.implementation({ from: proxyAdminAddress });
|
||||
expect(implementation).to.be.equal(this.implementationV1);
|
||||
});
|
||||
|
||||
@ -108,7 +108,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
|
||||
});
|
||||
|
||||
it('upgrades to the requested implementation', async function () {
|
||||
const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress });
|
||||
const implementation = await this.proxy.implementation({ from: proxyAdminAddress });
|
||||
expect(implementation).to.be.equal(this.behavior.address);
|
||||
});
|
||||
|
||||
@ -173,7 +173,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
|
||||
});
|
||||
|
||||
it('upgrades to the requested version and emits an event', async function () {
|
||||
const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress });
|
||||
const implementation = await this.proxy.implementation({ from: proxyAdminAddress });
|
||||
expect(implementation).to.be.equal(this.behaviorV1.address);
|
||||
expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV1.address });
|
||||
});
|
||||
@ -199,7 +199,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
|
||||
});
|
||||
|
||||
it('upgrades to the requested version and emits an event', async function () {
|
||||
const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress });
|
||||
const implementation = await this.proxy.implementation({ from: proxyAdminAddress });
|
||||
expect(implementation).to.be.equal(this.behaviorV2.address);
|
||||
expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV2.address });
|
||||
});
|
||||
@ -228,7 +228,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
|
||||
});
|
||||
|
||||
it('upgrades to the requested version and emits an event', async function () {
|
||||
const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress });
|
||||
const implementation = await this.proxy.implementation({ from: proxyAdminAddress });
|
||||
expect(implementation).to.be.equal(this.behaviorV3.address);
|
||||
expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV3.address });
|
||||
});
|
||||
@ -274,7 +274,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
|
||||
});
|
||||
|
||||
it('assigns new proxy admin', async function () {
|
||||
const newProxyAdmin = await this.proxy.admin.call({ from: newAdmin });
|
||||
const newProxyAdmin = await this.proxy.admin({ from: newAdmin });
|
||||
expect(newProxyAdmin).to.be.equal(anotherAccount);
|
||||
});
|
||||
|
||||
@ -333,14 +333,23 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
|
||||
);
|
||||
});
|
||||
|
||||
context('when function names clash', function () {
|
||||
describe('when function names clash', function () {
|
||||
it('when sender is proxy admin should run the proxy function', async function () {
|
||||
const value = await this.proxy.admin.call({ from: proxyAdminAddress });
|
||||
const value = await this.proxy.admin({ from: proxyAdminAddress, value: 0 });
|
||||
expect(value).to.be.equal(proxyAdminAddress);
|
||||
});
|
||||
|
||||
it('when sender is other should delegate to implementation', async function () {
|
||||
const value = await this.proxy.admin.call({ from: anotherAccount });
|
||||
const value = await this.proxy.admin({ from: anotherAccount, value: 0 });
|
||||
expect(value).to.be.equal('0x0000000000000000000000000000000011111142');
|
||||
});
|
||||
|
||||
it('when sender is proxy admin value should not be accepted', async function () {
|
||||
await expectRevert.unspecified(this.proxy.admin({ from: proxyAdminAddress, value: 1 }));
|
||||
});
|
||||
|
||||
it('when sender is other value should be accepted', async function () {
|
||||
const value = await this.proxy.admin({ from: anotherAccount, value: 1 });
|
||||
expect(value).to.be.equal('0x0000000000000000000000000000000011111142');
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,12 +2,14 @@ const shouldBehaveLikeProxy = require('../Proxy.behaviour');
|
||||
const shouldBehaveLikeTransparentUpgradeableProxy = require('./TransparentUpgradeableProxy.behaviour');
|
||||
|
||||
const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy');
|
||||
const ITransparentUpgradeableProxy = artifacts.require('ITransparentUpgradeableProxy');
|
||||
|
||||
contract('TransparentUpgradeableProxy', function (accounts) {
|
||||
const [proxyAdminAddress, proxyAdminOwner] = accounts;
|
||||
|
||||
const createProxy = async function (logic, admin, initData, opts) {
|
||||
return TransparentUpgradeableProxy.new(logic, admin, initData, opts);
|
||||
const { address } = await TransparentUpgradeableProxy.new(logic, admin, initData, opts);
|
||||
return ITransparentUpgradeableProxy.at(address);
|
||||
};
|
||||
|
||||
shouldBehaveLikeProxy(createProxy, proxyAdminAddress, proxyAdminOwner);
|
||||
|
||||
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