From 023894deefe6af0cf1e6120df744dffaccaf9040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Thu, 29 Jun 2023 10:00:35 -0600 Subject: [PATCH 01/16] Add `ERC2771Forwarder` as an enhanced successor to `MinimalForwarder` (#4346) Co-authored-by: Francisco --- .changeset/blue-horses-do.md | 5 + .github/workflows/checks.yml | 1 + contracts/metatx/ERC2771Forwarder.sol | 289 ++++++++++++++++ contracts/metatx/MinimalForwarder.sol | 104 ------ contracts/metatx/README.adoc | 2 +- contracts/utils/cryptography/EIP712.sol | 2 +- test/metatx/ERC2771Context.test.js | 29 +- test/metatx/ERC2771Forwarder.test.js | 433 ++++++++++++++++++++++++ test/metatx/MinimalForwarder.test.js | 171 ---------- 9 files changed, 749 insertions(+), 287 deletions(-) create mode 100644 .changeset/blue-horses-do.md create mode 100644 contracts/metatx/ERC2771Forwarder.sol delete mode 100644 contracts/metatx/MinimalForwarder.sol create mode 100644 test/metatx/ERC2771Forwarder.test.js delete mode 100644 test/metatx/MinimalForwarder.test.js diff --git a/.changeset/blue-horses-do.md b/.changeset/blue-horses-do.md new file mode 100644 index 000000000..9df604fe4 --- /dev/null +++ b/.changeset/blue-horses-do.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': major +--- + +`ERC2771Forwarder`: Added `deadline` for expiring transactions, batching, and more secure handling of `msg.value`. diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 122d39564..15cc88e96 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -100,6 +100,7 @@ jobs: - uses: crytic/slither-action@v0.3.0 with: node-version: 18.15 + slither-version: 0.9.3 codespell: runs-on: ubuntu-latest diff --git a/contracts/metatx/ERC2771Forwarder.sol b/contracts/metatx/ERC2771Forwarder.sol new file mode 100644 index 000000000..651fdce0b --- /dev/null +++ b/contracts/metatx/ERC2771Forwarder.sol @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (metatx/ERC2771Forwarder.sol) + +pragma solidity ^0.8.19; + +import "../utils/cryptography/ECDSA.sol"; +import "../utils/cryptography/EIP712.sol"; +import "../utils/Nonces.sol"; +import "../utils/Address.sol"; + +/** + * @dev A forwarder compatible with ERC2771 contracts. See {ERC2771Context}. + * + * This forwarder operates on forward requests that include: + * + * * `from`: An address to operate on behalf of. It is required to be equal to the request signer. + * * `to`: The address that should be called. + * * `value`: The amount of native token to attach with the requested call. + * * `gas`: The amount of gas limit that will be forwarded with the requested call. + * * `nonce`: A unique transaction ordering identifier to avoid replayability and request invalidation. + * * `deadline`: A timestamp after which the request is not executable anymore. + * * `data`: Encoded `msg.data` to send with the requested call. + */ +contract ERC2771Forwarder is EIP712, Nonces { + using ECDSA for bytes32; + + struct ForwardRequestData { + address from; + address to; + uint256 value; + uint256 gas; + uint48 deadline; + bytes data; + bytes signature; + } + + bytes32 private constant _FORWARD_REQUEST_TYPEHASH = + keccak256( + "ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,uint48 deadline,bytes data)" + ); + + /** + * @dev Emitted when a `ForwardRequest` is executed. + * + * NOTE: An unsuccessful forward request could be due to an invalid signature, an expired deadline, + * or simply a revert in the requested call. The contract guarantees that the relayer is not able to force + * the requested call to run out of gas. + */ + event ExecutedForwardRequest(address indexed signer, uint256 nonce, bool success); + + /** + * @dev The request `from` doesn't match with the recovered `signer`. + */ + error ERC2771ForwarderInvalidSigner(address signer, address from); + + /** + * @dev The `requestedValue` doesn't match with the available `msgValue`. + */ + error ERC2771ForwarderMismatchedValue(uint256 requestedValue, uint256 msgValue); + + /** + * @dev The request `deadline` has expired. + */ + error ERC2771ForwarderExpiredRequest(uint48 deadline); + + /** + * @dev See {EIP712-constructor}. + */ + constructor(string memory name) EIP712(name, "1") {} + + /** + * @dev Returns `true` if a request is valid for a provided `signature` at the current block timestamp. + * + * A transaction is considered valid when it hasn't expired (deadline is not met), and the signer + * matches the `from` parameter of the signed request. + * + * NOTE: A request may return false here but it won't cause {executeBatch} to revert if a refund + * receiver is provided. + */ + function verify(ForwardRequestData calldata request) public view virtual returns (bool) { + (bool alive, bool signerMatch, ) = _validate(request); + return alive && signerMatch; + } + + /** + * @dev Executes a `request` on behalf of `signature`'s signer using the ERC-2771 protocol. The gas + * provided to the requested call may not be exactly the amount requested, but the call will not run + * out of gas. Will revert if the request is invalid or the call reverts, in this case the nonce is not consumed. + * + * Requirements: + * + * - The request value should be equal to the provided `msg.value`. + * - The request should be valid according to {verify}. + */ + function execute(ForwardRequestData calldata request) public payable virtual { + // We make sure that msg.value and request.value match exactly. + // If the request is invalid or the call reverts, this whole function + // will revert, ensuring value isn't stuck. + if (msg.value != request.value) { + revert ERC2771ForwarderMismatchedValue(request.value, msg.value); + } + + if (!_execute(request, true)) { + revert Address.FailedInnerCall(); + } + } + + /** + * @dev Batch version of {execute} with optional refunding and atomic execution. + * + * In case a batch contains at least one invalid request (see {verify}), the + * request will be skipped and the `refundReceiver` parameter will receive back the + * unused requested value at the end of the execution. This is done to prevent reverting + * the entire batch when a request is invalid or has already been submitted. + * + * If the `refundReceiver` is the `address(0)`, this function will revert when at least + * one of the requests was not valid instead of skipping it. This could be useful if + * a batch is required to get executed atomically (at least at the top-level). For example, + * refunding (and thus atomicity) can be opt-out if the relayer is using a service that avoids + * including reverted transactions. + * + * Requirements: + * + * - The sum of the requests' values should be equal to the provided `msg.value`. + * - All of the requests should be valid (see {verify}) when `refundReceiver` is the zero address. + * + * NOTE: Setting a zero `refundReceiver` guarantees an all-or-nothing requests execution only for + * the first-level forwarded calls. In case a forwarded request calls to a contract with another + * subcall, the second-level call may revert without the top-level call reverting. + */ + function executeBatch( + ForwardRequestData[] calldata requests, + address payable refundReceiver + ) public payable virtual { + bool atomic = refundReceiver == address(0); + + uint256 requestsValue; + uint256 refundValue; + + for (uint256 i; i < requests.length; ++i) { + requestsValue += requests[i].value; + bool success = _execute(requests[i], atomic); + if (!success) { + refundValue += requests[i].value; + } + } + + // The batch should revert if there's a mismatched msg.value provided + // to avoid request value tampering + if (requestsValue != msg.value) { + revert ERC2771ForwarderMismatchedValue(requestsValue, msg.value); + } + + // Some requests with value were invalid (possibly due to frontrunning). + // To avoid leaving ETH in the contract this value is refunded. + if (refundValue != 0) { + // We know refundReceiver != address(0) && requestsValue == msg.value + // meaning we can ensure refundValue is not taken from the original contract's balance + // and refundReceiver is a known account. + Address.sendValue(refundReceiver, refundValue); + } + } + + /** + * @dev Validates if the provided request can be executed at current block timestamp with + * the given `request.signature` on behalf of `request.signer`. + */ + function _validate( + ForwardRequestData calldata request + ) internal view virtual returns (bool alive, bool signerMatch, address signer) { + signer = _recoverForwardRequestSigner(request); + return (request.deadline >= block.timestamp, signer == request.from, signer); + } + + /** + * @dev Recovers the signer of an EIP712 message hash for a forward `request` and its corresponding `signature`. + * See {ECDSA-recover}. + */ + function _recoverForwardRequestSigner(ForwardRequestData calldata request) internal view virtual returns (address) { + return + _hashTypedDataV4( + keccak256( + abi.encode( + _FORWARD_REQUEST_TYPEHASH, + request.from, + request.to, + request.value, + request.gas, + nonces(request.from), + request.deadline, + keccak256(request.data) + ) + ) + ).recover(request.signature); + } + + /** + * @dev Validates and executes a signed request returning the request call `success` value. + * + * Internal function without msg.value validation. + * + * Requirements: + * + * - The caller must have provided enough gas to forward with the call. + * - The request must be valid (see {verify}) if the `requireValidRequest` is true. + * + * Emits an {ExecutedForwardRequest} event. + * + * IMPORTANT: Using this function doesn't check that all the `msg.value` was sent, potentially + * leaving value stuck in the contract. + */ + function _execute( + ForwardRequestData calldata request, + bool requireValidRequest + ) internal virtual returns (bool success) { + (bool alive, bool signerMatch, address signer) = _validate(request); + + // Need to explicitly specify if a revert is required since non-reverting is default for + // batches and reversion is opt-in since it could be useful in some scenarios + if (requireValidRequest) { + if (!alive) { + revert ERC2771ForwarderExpiredRequest(request.deadline); + } + + if (!signerMatch) { + revert ERC2771ForwarderInvalidSigner(signer, request.from); + } + } + + // Ignore an invalid request because requireValidRequest = false + if (signerMatch && alive) { + // Nonce should be used before the call to prevent reusing by reentrancy + uint256 currentNonce = _useNonce(signer); + + (success, ) = request.to.call{gas: request.gas, value: request.value}( + abi.encodePacked(request.data, request.from) + ); + + _checkForwardedGas(request); + + emit ExecutedForwardRequest(signer, currentNonce, success); + } + } + + /** + * @dev Checks if the requested gas was correctly forwarded to the callee. + * + * As a consequence of https://eips.ethereum.org/EIPS/eip-150[EIP-150]: + * - At most `gasleft() - floor(gasleft() / 64)` is forwarded to the callee. + * - At least `floor(gasleft() / 64)` is kept in the caller. + * + * It reverts consuming all the available gas if the forwarded gas is not the requested gas. + * + * IMPORTANT: This function should be called exactly the end of the forwarded call. Any gas consumed + * in between will make room for bypassing this check. + */ + function _checkForwardedGas(ForwardRequestData calldata request) private view { + // To avoid insufficient gas griefing attacks, as referenced in https://ronan.eth.limo/blog/ethereum-gas-dangers/ + // + // A malicious relayer can attempt to shrink the gas forwarded so that the underlying call reverts out-of-gas + // but the forwarding itself still succeeds. In order to make sure that the subcall received sufficient gas, + // we will inspect gasleft() after the forwarding. + // + // Let X be the gas available before the subcall, such that the subcall gets at most X * 63 / 64. + // We can't know X after CALL dynamic costs, but we want it to be such that X * 63 / 64 >= req.gas. + // Let Y be the gas used in the subcall. gasleft() measured immediately after the subcall will be gasleft() = X - Y. + // If the subcall ran out of gas, then Y = X * 63 / 64 and gasleft() = X - Y = X / 64. + // Under this assumption req.gas / 63 > gasleft() is true is true if and only if + // req.gas / 63 > X / 64, or equivalently req.gas > X * 63 / 64. + // This means that if the subcall runs out of gas we are able to detect that insufficient gas was passed. + // + // We will now also see that req.gas / 63 > gasleft() implies that req.gas >= X * 63 / 64. + // The contract guarantees Y <= req.gas, thus gasleft() = X - Y >= X - req.gas. + // - req.gas / 63 > gasleft() + // - req.gas / 63 >= X - req.gas + // - req.gas >= X * 63 / 64 + // In other words if req.gas < X * 63 / 64 then req.gas / 63 <= gasleft(), thus if the relayer behaves honestly + // the forwarding does not revert. + if (gasleft() < request.gas / 63) { + // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since + // neither revert or assert consume all gas since Solidity 0.8.0 + // https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require + /// @solidity memory-safe-assembly + assembly { + invalid() + } + } + } +} diff --git a/contracts/metatx/MinimalForwarder.sol b/contracts/metatx/MinimalForwarder.sol deleted file mode 100644 index b5267aa10..000000000 --- a/contracts/metatx/MinimalForwarder.sol +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.9.0) (metatx/MinimalForwarder.sol) - -pragma solidity ^0.8.19; - -import "../utils/cryptography/ECDSA.sol"; -import "../utils/cryptography/EIP712.sol"; - -/** - * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}. - * - * MinimalForwarder is mainly meant for testing, as it is missing features to be a good production-ready forwarder. This - * contract does not intend to have all the properties that are needed for a sound forwarding system. A fully - * functioning forwarding system with good properties requires more complexity. We suggest you look at other projects - * such as the GSN which do have the goal of building a system like that. - */ -contract MinimalForwarder is EIP712 { - using ECDSA for bytes32; - - struct ForwardRequest { - address from; - address to; - uint256 value; - uint256 gas; - uint256 nonce; - bytes data; - } - - bytes32 private constant _TYPEHASH = - keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)"); - - mapping(address => uint256) private _nonces; - - /** - * @dev The request `from` doesn't match with the recovered `signer`. - */ - error MinimalForwarderInvalidSigner(address signer, address from); - - /** - * @dev The request nonce doesn't match with the `current` nonce for the request signer. - */ - error MinimalForwarderInvalidNonce(address signer, uint256 current); - - constructor() EIP712("MinimalForwarder", "0.0.1") {} - - function getNonce(address from) public view returns (uint256) { - return _nonces[from]; - } - - function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) { - address signer = _recover(req, signature); - (bool correctFrom, bool correctNonce) = _validateReq(req, signer); - return correctFrom && correctNonce; - } - - function execute( - ForwardRequest calldata req, - bytes calldata signature - ) public payable returns (bool, bytes memory) { - address signer = _recover(req, signature); - (bool correctFrom, bool correctNonce) = _validateReq(req, signer); - - if (!correctFrom) { - revert MinimalForwarderInvalidSigner(signer, req.from); - } - if (!correctNonce) { - revert MinimalForwarderInvalidNonce(signer, _nonces[req.from]); - } - - _nonces[req.from] = req.nonce + 1; - - (bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}( - abi.encodePacked(req.data, req.from) - ); - - // Validate that the relayer has sent enough gas for the call. - // See https://ronan.eth.limo/blog/ethereum-gas-dangers/ - if (gasleft() <= req.gas / 63) { - // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since - // neither revert or assert consume all gas since Solidity 0.8.0 - // https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require - /// @solidity memory-safe-assembly - assembly { - invalid() - } - } - - return (success, returndata); - } - - function _recover(ForwardRequest calldata req, bytes calldata signature) internal view returns (address) { - return - _hashTypedDataV4( - keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data))) - ).recover(signature); - } - - function _validateReq( - ForwardRequest calldata req, - address signer - ) internal view returns (bool correctFrom, bool correctNonce) { - return (signer == req.from, _nonces[req.from] == req.nonce); - } -} diff --git a/contracts/metatx/README.adoc b/contracts/metatx/README.adoc index eccdeaf97..9f25802e4 100644 --- a/contracts/metatx/README.adoc +++ b/contracts/metatx/README.adoc @@ -9,4 +9,4 @@ NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/ == Utils -{{MinimalForwarder}} +{{ERC2771Forwarder}} diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol index 2628014f1..1089de005 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -110,7 +110,7 @@ abstract contract EIP712 is IERC5267 { } /** - * @dev See {EIP-5267}. + * @dev See {IERC-5267}. * * _Available since v4.9._ */ diff --git a/test/metatx/ERC2771Context.test.js b/test/metatx/ERC2771Context.test.js index 6c298d3d9..3dd4b4153 100644 --- a/test/metatx/ERC2771Context.test.js +++ b/test/metatx/ERC2771Context.test.js @@ -6,14 +6,16 @@ const { expectEvent } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const ERC2771ContextMock = artifacts.require('ERC2771ContextMock'); -const MinimalForwarder = artifacts.require('MinimalForwarder'); +const ERC2771Forwarder = artifacts.require('ERC2771Forwarder'); const ContextMockCaller = artifacts.require('ContextMockCaller'); const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior'); contract('ERC2771Context', function (accounts) { + const MAX_UINT48 = web3.utils.toBN(1).shln(48).subn(1).toString(); + beforeEach(async function () { - this.forwarder = await MinimalForwarder.new(); + this.forwarder = await ERC2771Forwarder.new('ERC2771Forwarder'); this.recipient = await ERC2771ContextMock.new(this.forwarder.address); this.domain = await getDomain(this.forwarder); @@ -25,6 +27,7 @@ contract('ERC2771Context', function (accounts) { { name: 'value', type: 'uint256' }, { name: 'gas', type: 'uint256' }, { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint48' }, { name: 'data', type: 'bytes' }, ], }; @@ -63,14 +66,17 @@ contract('ERC2771Context', function (accounts) { to: this.recipient.address, value: '0', gas: '100000', - nonce: (await this.forwarder.getNonce(this.sender)).toString(), + nonce: (await this.forwarder.nonces(this.sender)).toString(), + deadline: MAX_UINT48, data, }; - const sign = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { data: { ...this.data, message: req } }); - expect(await this.forwarder.verify(req, sign)).to.equal(true); + req.signature = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { + data: { ...this.data, message: req }, + }); + expect(await this.forwarder.verify(req)).to.equal(true); - const { tx } = await this.forwarder.execute(req, sign); + const { tx } = await this.forwarder.execute(req); await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Sender', { sender: this.sender }); }); }); @@ -86,14 +92,17 @@ contract('ERC2771Context', function (accounts) { to: this.recipient.address, value: '0', gas: '100000', - nonce: (await this.forwarder.getNonce(this.sender)).toString(), + nonce: (await this.forwarder.nonces(this.sender)).toString(), + deadline: MAX_UINT48, data, }; - const sign = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { data: { ...this.data, message: req } }); - expect(await this.forwarder.verify(req, sign)).to.equal(true); + req.signature = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { + data: { ...this.data, message: req }, + }); + expect(await this.forwarder.verify(req)).to.equal(true); - const { tx } = await this.forwarder.execute(req, sign); + const { tx } = await this.forwarder.execute(req); await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Data', { data, integerValue, stringValue }); }); }); diff --git a/test/metatx/ERC2771Forwarder.test.js b/test/metatx/ERC2771Forwarder.test.js new file mode 100644 index 000000000..fa84ccdc3 --- /dev/null +++ b/test/metatx/ERC2771Forwarder.test.js @@ -0,0 +1,433 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { constants, expectRevert, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC2771Forwarder = artifacts.require('ERC2771Forwarder'); +const CallReceiverMock = artifacts.require('CallReceiverMock'); + +contract('ERC2771Forwarder', function (accounts) { + const [, refundReceiver, another] = accounts; + + const tamperedValues = { + from: another, + to: another, + value: web3.utils.toWei('0.5'), + data: '0x1742', + deadline: 0xdeadbeef, + }; + + beforeEach(async function () { + this.forwarder = await ERC2771Forwarder.new('ERC2771Forwarder'); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint48' }, + { name: 'data', type: 'bytes' }, + ], + }; + + this.alice = Wallet.generate(); + this.alice.address = web3.utils.toChecksumAddress(this.alice.getAddressString()); + + this.timestamp = await time.latest(); + this.request = { + from: this.alice.address, + to: constants.ZERO_ADDRESS, + value: '0', + gas: '100000', + data: '0x', + deadline: this.timestamp.toNumber() + 60, // 1 minute + }; + this.requestData = { + ...this.request, + nonce: (await this.forwarder.nonces(this.alice.address)).toString(), + }; + + this.forgeData = request => ({ + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + message: { ...this.requestData, ...request }, + }); + this.sign = (privateKey, request) => + ethSigUtil.signTypedMessage(privateKey, { + data: this.forgeData(request), + }); + + this.requestData.signature = this.sign(this.alice.getPrivateKey()); + }); + + context('verify', function () { + context('with valid signature', function () { + it('returns true without altering the nonce', async function () { + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + expect(await this.forwarder.verify(this.requestData)).to.be.equal(true); + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + }); + }); + + context('with tampered values', function () { + for (const [key, value] of Object.entries(tamperedValues)) { + it(`returns false with tampered ${key}`, async function () { + expect(await this.forwarder.verify(this.forgeData({ [key]: value }).message)).to.be.equal(false); + }); + } + + it('returns false with tampered signature', async function () { + const tamperedsign = web3.utils.hexToBytes(this.requestData.signature); + tamperedsign[42] ^= 0xff; + this.requestData.signature = web3.utils.bytesToHex(tamperedsign); + expect(await this.forwarder.verify(this.requestData)).to.be.equal(false); + }); + + it('returns false with valid signature for non-current nonce', async function () { + const req = { + ...this.requestData, + nonce: this.requestData.nonce + 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + expect(await this.forwarder.verify(req)).to.be.equal(false); + }); + + it('returns false with valid signature for expired deadline', async function () { + const req = { + ...this.requestData, + deadline: this.timestamp - 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + expect(await this.forwarder.verify(req)).to.be.equal(false); + }); + }); + }); + + context('execute', function () { + context('with valid requests', function () { + beforeEach(async function () { + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + }); + + it('emits an event and consumes nonce for a successful request', async function () { + const receipt = await this.forwarder.execute(this.requestData); + expectEvent(receipt, 'ExecutedForwardRequest', { + signer: this.requestData.from, + nonce: web3.utils.toBN(this.requestData.nonce), + success: true, + }); + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce + 1), + ); + }); + + it('reverts with an unsuccessful request', async function () { + const receiver = await CallReceiverMock.new(); + const req = { + ...this.requestData, + to: receiver.address, + data: receiver.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'FailedInnerCall', []); + }); + }); + + context('with tampered request', function () { + for (const [key, value] of Object.entries(tamperedValues)) { + it(`reverts with tampered ${key}`, async function () { + const data = this.forgeData({ [key]: value }); + await expectRevertCustomError( + this.forwarder.execute(data.message, { + value: key == 'value' ? value : 0, // To avoid MismatchedValue error + }), + 'ERC2771ForwarderInvalidSigner', + [ethSigUtil.recoverTypedSignature({ data, sig: this.requestData.signature }), data.message.from], + ); + }); + } + + it('reverts with tampered signature', async function () { + const tamperedSig = web3.utils.hexToBytes(this.requestData.signature); + tamperedSig[42] ^= 0xff; + this.requestData.signature = web3.utils.bytesToHex(tamperedSig); + await expectRevertCustomError(this.forwarder.execute(this.requestData), 'ERC2771ForwarderInvalidSigner', [ + ethSigUtil.recoverTypedSignature({ data: this.forgeData(), sig: tamperedSig }), + this.requestData.from, + ]); + }); + + it('reverts with valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestData); + + // And then fail due to an already used nonce + await expectRevertCustomError(this.forwarder.execute(this.requestData), 'ERC2771ForwarderInvalidSigner', [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData({ ...this.requestData, nonce: this.requestData.nonce + 1 }), + sig: this.requestData.signature, + }), + this.requestData.from, + ]); + }); + + it('reverts with valid signature for expired deadline', async function () { + const req = { + ...this.requestData, + deadline: this.timestamp - 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'ERC2771ForwarderExpiredRequest', [ + this.timestamp - 1, + ]); + }); + + it('reverts with valid signature but mismatched value', async function () { + const value = 100; + const req = { + ...this.requestData, + value, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'ERC2771ForwarderMismatchedValue', [0, value]); + }); + }); + + it('bubbles out of gas', async function () { + const receiver = await CallReceiverMock.new(); + const gasAvailable = 100000; + this.requestData.to = receiver.address; + this.requestData.data = receiver.contract.methods.mockFunctionOutOfGas().encodeABI(); + this.requestData.gas = 1000000; + + this.requestData.signature = this.sign(this.alice.getPrivateKey()); + + await expectRevert.assertion(this.forwarder.execute(this.requestData, { gas: gasAvailable })); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + expect(gasUsed).to.be.equal(gasAvailable); + }); + }); + + context('executeBatch', function () { + const batchValue = requestDatas => requestDatas.reduce((value, request) => value + Number(request.value), 0); + + beforeEach(async function () { + this.bob = Wallet.generate(); + this.bob.address = web3.utils.toChecksumAddress(this.bob.getAddressString()); + + this.eve = Wallet.generate(); + this.eve.address = web3.utils.toChecksumAddress(this.eve.getAddressString()); + + this.signers = [this.alice, this.bob, this.eve]; + + this.requestDatas = await Promise.all( + this.signers.map(async ({ address }) => ({ + ...this.requestData, + from: address, + nonce: (await this.forwarder.nonces(address)).toString(), + value: web3.utils.toWei('10', 'gwei'), + })), + ); + + this.requestDatas = this.requestDatas.map((requestData, i) => ({ + ...requestData, + signature: this.sign(this.signers[i].getPrivateKey(), requestData), + })); + + this.msgValue = batchValue(this.requestDatas); + }); + + context('with valid requests', function () { + beforeEach(async function () { + for (const request of this.requestDatas) { + expect(await this.forwarder.verify(request)).to.be.equal(true); + } + + this.receipt = await this.forwarder.executeBatch(this.requestDatas, another, { value: this.msgValue }); + }); + + it('emits events', async function () { + for (const request of this.requestDatas) { + expectEvent(this.receipt, 'ExecutedForwardRequest', { + signer: request.from, + nonce: web3.utils.toBN(request.nonce), + success: true, + }); + } + }); + + it('increase nonces', async function () { + for (const request of this.requestDatas) { + expect(await this.forwarder.nonces(request.from)).to.be.bignumber.eq(web3.utils.toBN(request.nonce + 1)); + } + }); + }); + + context('with tampered requests', function () { + beforeEach(async function () { + this.idx = 1; // Tampered idx + }); + + it('reverts with mismatched value', async function () { + this.requestDatas[this.idx].value = 100; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, another, { value: this.msgValue }), + 'ERC2771ForwarderMismatchedValue', + [batchValue(this.requestDatas), this.msgValue], + ); + }); + + context('when the refund receiver is the zero address', function () { + beforeEach(function () { + this.refundReceiver = constants.ZERO_ADDRESS; + }); + + for (const [key, value] of Object.entries(tamperedValues)) { + it(`reverts with at least one tampered request ${key}`, async function () { + const data = this.forgeData({ ...this.requestDatas[this.idx], [key]: value }); + + this.requestDatas[this.idx] = data.message; + + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ data, sig: this.requestDatas[this.idx].signature }), + data.message.from, + ], + ); + }); + } + + it('reverts with at least one tampered request signature', async function () { + const tamperedSig = web3.utils.hexToBytes(this.requestDatas[this.idx].signature); + tamperedSig[42] ^= 0xff; + + this.requestDatas[this.idx].signature = web3.utils.bytesToHex(tamperedSig); + + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData(this.requestDatas[this.idx]), + sig: this.requestDatas[this.idx].signature, + }), + this.requestDatas[this.idx].from, + ], + ); + }); + + it('reverts with at least one valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestDatas[this.idx], { value: this.requestDatas[this.idx].value }); + + // And then fail due to an already used nonce + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData({ ...this.requestDatas[this.idx], nonce: this.requestDatas[this.idx].nonce + 1 }), + sig: this.requestDatas[this.idx].signature, + }), + this.requestDatas[this.idx].from, + ], + ); + }); + + it('reverts with at least one valid signature for expired deadline', async function () { + this.requestDatas[this.idx].deadline = this.timestamp.toNumber() - 1; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderExpiredRequest', + [this.timestamp.toNumber() - 1], + ); + }); + }); + + context('when the refund receiver is a known address', function () { + beforeEach(async function () { + this.refundReceiver = refundReceiver; + this.initialRefundReceiverBalance = web3.utils.toBN(await web3.eth.getBalance(this.refundReceiver)); + this.initialTamperedRequestNonce = await this.forwarder.nonces(this.requestDatas[this.idx].from); + }); + + for (const [key, value] of Object.entries(tamperedValues)) { + it(`ignores a request with tampered ${key} and refunds its value`, async function () { + const data = this.forgeData({ ...this.requestDatas[this.idx], [key]: value }); + + this.requestDatas[this.idx] = data.message; + + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: batchValue(this.requestDatas), + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + } + + it('ignores a request with a valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestDatas[this.idx], { value: this.requestDatas[this.idx].value }); + this.initialTamperedRequestNonce++; // Should be already incremented by the individual `execute` + + // And then ignore the same request in a batch due to an already used nonce + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: this.msgValue, + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + + it('ignores a request with a valid signature for expired deadline', async function () { + this.requestDatas[this.idx].deadline = this.timestamp.toNumber() - 1; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: this.msgValue, + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + + afterEach(async function () { + // The invalid request value was refunded + expect(await web3.eth.getBalance(this.refundReceiver)).to.be.bignumber.equal( + this.initialRefundReceiverBalance.add(web3.utils.toBN(this.requestDatas[this.idx].value)), + ); + + // The invalid request from's nonce was not incremented + expect(await this.forwarder.nonces(this.requestDatas[this.idx].from)).to.be.bignumber.eq( + web3.utils.toBN(this.initialTamperedRequestNonce), + ); + }); + }); + }); + }); +}); diff --git a/test/metatx/MinimalForwarder.test.js b/test/metatx/MinimalForwarder.test.js deleted file mode 100644 index c775c5e44..000000000 --- a/test/metatx/MinimalForwarder.test.js +++ /dev/null @@ -1,171 +0,0 @@ -const ethSigUtil = require('eth-sig-util'); -const Wallet = require('ethereumjs-wallet').default; -const { getDomain, domainType } = require('../helpers/eip712'); -const { expectRevertCustomError } = require('../helpers/customError'); - -const { constants, expectRevert } = require('@openzeppelin/test-helpers'); -const { expect } = require('chai'); - -const MinimalForwarder = artifacts.require('MinimalForwarder'); -const CallReceiverMock = artifacts.require('CallReceiverMock'); - -contract('MinimalForwarder', function (accounts) { - beforeEach(async function () { - this.forwarder = await MinimalForwarder.new(); - - this.domain = await getDomain(this.forwarder); - this.types = { - EIP712Domain: domainType(this.domain), - ForwardRequest: [ - { name: 'from', type: 'address' }, - { name: 'to', type: 'address' }, - { name: 'value', type: 'uint256' }, - { name: 'gas', type: 'uint256' }, - { name: 'nonce', type: 'uint256' }, - { name: 'data', type: 'bytes' }, - ], - }; - }); - - context('with message', function () { - const tamperedValues = { - from: accounts[0], - to: accounts[0], - value: web3.utils.toWei('1'), - nonce: 1234, - data: '0x1742', - }; - - beforeEach(async function () { - this.wallet = Wallet.generate(); - this.sender = web3.utils.toChecksumAddress(this.wallet.getAddressString()); - this.req = { - from: this.sender, - to: constants.ZERO_ADDRESS, - value: '0', - gas: '100000', - nonce: Number(await this.forwarder.getNonce(this.sender)), - data: '0x', - }; - this.forgeData = req => ({ - types: this.types, - domain: this.domain, - primaryType: 'ForwardRequest', - message: { ...this.req, ...req }, - }); - this.sign = req => - ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { - data: this.forgeData(req), - }); - }); - - context('verify', function () { - context('valid signature', function () { - beforeEach(async function () { - expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); - }); - - it('success', async function () { - expect(await this.forwarder.verify(this.req, this.sign())).to.be.equal(true); - }); - - afterEach(async function () { - expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); - }); - }); - - context('with tampered values', function () { - for (const [key, value] of Object.entries(tamperedValues)) { - it(`returns false with tampered ${key}`, async function () { - expect(await this.forwarder.verify(this.forgeData({ [key]: value }).message, this.sign())).to.be.equal( - false, - ); - }); - } - - it('returns false with tampered signature', async function () { - const tamperedsign = web3.utils.hexToBytes(this.sign()); - tamperedsign[42] ^= 0xff; - expect(await this.forwarder.verify(this.req, web3.utils.bytesToHex(tamperedsign))).to.be.equal(false); - }); - - it('returns false with valid signature for non-current nonce', async function () { - const req = { - ...this.req, - nonce: this.req.nonce + 1, - }; - const sig = this.sign(req); - expect(await this.forwarder.verify(req, sig)).to.be.equal(false); - }); - }); - }); - - context('execute', function () { - context('valid signature', function () { - beforeEach(async function () { - expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); - }); - - it('success', async function () { - await this.forwarder.execute(this.req, this.sign()); // expect to not revert - }); - - afterEach(async function () { - expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal( - web3.utils.toBN(this.req.nonce + 1), - ); - }); - }); - - context('with tampered values', function () { - for (const [key, value] of Object.entries(tamperedValues)) { - it(`reverts with tampered ${key}`, async function () { - const sig = this.sign(); - const data = this.forgeData({ [key]: value }); - await expectRevertCustomError(this.forwarder.execute(data.message, sig), 'MinimalForwarderInvalidSigner', [ - ethSigUtil.recoverTypedSignature({ data, sig }), - data.message.from, - ]); - }); - } - - it('reverts with tampered signature', async function () { - const tamperedSig = web3.utils.hexToBytes(this.sign()); - tamperedSig[42] ^= 0xff; - await expectRevertCustomError( - this.forwarder.execute(this.req, web3.utils.bytesToHex(tamperedSig)), - 'MinimalForwarderInvalidSigner', - [ethSigUtil.recoverTypedSignature({ data: this.forgeData(), sig: tamperedSig }), this.req.from], - ); - }); - - it('reverts with valid signature for non-current nonce', async function () { - const req = { - ...this.req, - nonce: this.req.nonce + 1, - }; - const sig = this.sign(req); - await expectRevertCustomError(this.forwarder.execute(req, sig), 'MinimalForwarderInvalidNonce', [ - this.req.from, - this.req.nonce, - ]); - }); - }); - - it('bubble out of gas', async function () { - const receiver = await CallReceiverMock.new(); - const gasAvailable = 100000; - this.req.to = receiver.address; - this.req.data = receiver.contract.methods.mockFunctionOutOfGas().encodeABI(); - this.req.gas = 1000000; - - await expectRevert.assertion(this.forwarder.execute(this.req, this.sign(), { gas: gasAvailable })); - - const { transactions } = await web3.eth.getBlock('latest'); - const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); - - expect(gasUsed).to.be.equal(gasAvailable); - }); - }); - }); -}); From d6a8b2ccd7dfd9001942233d6ce0bbecbaab1771 Mon Sep 17 00:00:00 2001 From: Renan Souza Date: Thu, 29 Jun 2023 13:41:44 -0300 Subject: [PATCH 02/16] Fix details AccessControl-test (#4391) --- test/access/AccessControl.behavior.js | 2 +- test/access/AccessControlEnumerable.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/access/AccessControl.behavior.js b/test/access/AccessControl.behavior.js index b1729c5d6..20804f049 100644 --- a/test/access/AccessControl.behavior.js +++ b/test/access/AccessControl.behavior.js @@ -382,7 +382,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(delay, defaultAdmin, new it("should revert if defaultAdmin's admin is changed", async function () { await expectRevertCustomError( - this.accessControl.$_setRoleAdmin(DEFAULT_ADMIN_ROLE, defaultAdmin), + this.accessControl.$_setRoleAdmin(DEFAULT_ADMIN_ROLE, OTHER_ROLE), 'AccessControlEnforcedDefaultAdminRules', [], ); diff --git a/test/access/AccessControlEnumerable.test.js b/test/access/AccessControlEnumerable.test.js index 0e1879700..429f22f8f 100644 --- a/test/access/AccessControlEnumerable.test.js +++ b/test/access/AccessControlEnumerable.test.js @@ -6,7 +6,7 @@ const { const AccessControlEnumerable = artifacts.require('$AccessControlEnumerable'); -contract('AccessControl', function (accounts) { +contract('AccessControlEnumerable', function (accounts) { beforeEach(async function () { this.accessControl = await AccessControlEnumerable.new({ from: accounts[0] }); await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); From 874c2d3c02ec1bce6af9a30bc828d3fe2079136b Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 29 Jun 2023 17:12:26 -0300 Subject: [PATCH 03/16] Use explicit imports (#4399) Co-authored-by: Hadrien Croubois Co-authored-by: ernestognw --- .changeset/orange-apes-draw.md | 5 +++ .solhint.json | 3 +- README.md | 2 +- contracts/access/AccessControl.sol | 8 ++-- .../access/AccessControlDefaultAdminRules.sol | 9 +++-- contracts/access/AccessControlEnumerable.sol | 6 +-- .../IAccessControlDefaultAdminRules.sol | 2 +- contracts/access/IAccessControlEnumerable.sol | 2 +- contracts/access/Ownable.sol | 2 +- contracts/access/Ownable2Step.sol | 2 +- contracts/finance/VestingWallet.sol | 7 ++-- contracts/governance/Governor.sol | 20 +++++----- contracts/governance/IGovernor.sol | 4 +- contracts/governance/TimelockController.sol | 9 +++-- .../GovernorCompatibilityBravo.sol | 8 ++-- .../IGovernorCompatibilityBravo.sol | 2 +- .../extensions/GovernorCountingSimple.sol | 2 +- .../extensions/GovernorPreventLateQuorum.sol | 4 +- .../extensions/GovernorSettings.sol | 2 +- .../extensions/GovernorTimelockCompound.sol | 10 +++-- .../extensions/GovernorTimelockControl.sol | 7 ++-- .../governance/extensions/GovernorVotes.sol | 6 ++- .../GovernorVotesQuorumFraction.sol | 6 +-- .../extensions/IGovernorTimelock.sol | 2 +- contracts/governance/utils/Votes.sol | 12 +++--- contracts/interfaces/IERC1155.sol | 2 +- contracts/interfaces/IERC1155MetadataURI.sol | 2 +- contracts/interfaces/IERC1155Receiver.sol | 2 +- contracts/interfaces/IERC1363.sol | 4 +- contracts/interfaces/IERC165.sol | 2 +- contracts/interfaces/IERC20.sol | 2 +- contracts/interfaces/IERC20Metadata.sol | 2 +- contracts/interfaces/IERC2612.sol | 2 +- contracts/interfaces/IERC2981.sol | 2 +- contracts/interfaces/IERC3156.sol | 4 +- contracts/interfaces/IERC3156FlashLender.sol | 2 +- contracts/interfaces/IERC4626.sol | 4 +- contracts/interfaces/IERC4906.sol | 4 +- contracts/interfaces/IERC5805.sol | 4 +- contracts/interfaces/IERC721.sol | 2 +- contracts/interfaces/IERC721Enumerable.sol | 2 +- contracts/interfaces/IERC721Metadata.sol | 2 +- contracts/interfaces/IERC721Receiver.sol | 2 +- contracts/metatx/ERC2771Context.sol | 2 +- contracts/metatx/ERC2771Forwarder.sol | 8 ++-- contracts/mocks/AddressFnPointersMock.sol | 2 +- contracts/mocks/ArraysMock.sol | 2 +- contracts/mocks/ContextMock.sol | 2 +- contracts/mocks/DummyImplementation.sol | 3 +- contracts/mocks/EIP712Verifier.sol | 4 +- contracts/mocks/ERC1271WalletMock.sol | 6 +-- .../ERC165/ERC165InterfacesSupported.sol | 2 +- contracts/mocks/ERC165/ERC165ReturnBomb.sol | 2 +- contracts/mocks/ERC2771ContextMock.sol | 5 ++- contracts/mocks/ERC3156FlashBorrowerMock.sol | 6 +-- contracts/mocks/InitializableMock.sol | 2 +- contracts/mocks/MulticallTest.sol | 2 +- .../MultipleInheritanceInitializableMocks.sol | 2 +- contracts/mocks/PausableMock.sol | 2 +- contracts/mocks/ReentrancyAttack.sol | 2 +- contracts/mocks/ReentrancyMock.sol | 4 +- contracts/mocks/RegressionImplementation.sol | 2 +- .../SingleInheritanceInitializableMocks.sol | 2 +- contracts/mocks/StorageSlotMock.sol | 2 +- contracts/mocks/TimelockReentrant.sol | 2 +- contracts/mocks/VotesMock.sol | 2 +- contracts/mocks/docs/ERC4626Fees.sol | 5 ++- .../mocks/docs/governance/MyGovernor.sol | 13 ++++--- contracts/mocks/docs/governance/MyToken.sol | 7 ++-- .../docs/governance/MyTokenTimestampBased.sol | 7 ++-- .../mocks/docs/governance/MyTokenWrapped.sol | 9 +++-- .../GovernorCompatibilityBravoMock.sol | 10 +++-- contracts/mocks/governance/GovernorMock.sol | 7 ++-- .../GovernorPreventLateQuorumMock.sol | 9 +++-- .../GovernorTimelockCompoundMock.sol | 9 +++-- .../GovernorTimelockControlMock.sol | 9 +++-- .../mocks/governance/GovernorVoteMock.sol | 4 +- .../governance/GovernorWithParamsMock.sol | 5 ++- contracts/mocks/proxy/UUPSUpgradeableMock.sol | 3 +- contracts/mocks/token/ERC1155ReceiverMock.sol | 4 +- contracts/mocks/token/ERC20ApprovalMock.sol | 2 +- contracts/mocks/token/ERC20DecimalsMock.sol | 2 +- contracts/mocks/token/ERC20FlashMintMock.sol | 2 +- .../mocks/token/ERC20ForceApproveMock.sol | 2 +- contracts/mocks/token/ERC20Mock.sol | 2 +- contracts/mocks/token/ERC20MulticallMock.sol | 4 +- contracts/mocks/token/ERC20NoReturnMock.sol | 2 +- .../mocks/token/ERC20PermitNoRevertMock.sol | 4 +- contracts/mocks/token/ERC20Reentrant.sol | 4 +- .../mocks/token/ERC20ReturnFalseMock.sol | 2 +- .../mocks/token/ERC20VotesLegacyMock.sol | 10 ++--- contracts/mocks/token/ERC4626LimitsMock.sol | 2 +- contracts/mocks/token/ERC4626Mock.sol | 3 +- contracts/mocks/token/ERC4626OffsetMock.sol | 2 +- contracts/mocks/token/ERC4646FeesMock.sol | 2 +- .../token/ERC721ConsecutiveEnumerableMock.sol | 5 ++- .../mocks/token/ERC721ConsecutiveMock.sol | 8 ++-- contracts/mocks/token/ERC721ReceiverMock.sol | 2 +- .../mocks/token/ERC721URIStorageMock.sol | 2 +- contracts/mocks/token/VotesTimestamp.sol | 5 ++- contracts/proxy/ERC1967/ERC1967Proxy.sol | 4 +- contracts/proxy/ERC1967/ERC1967Utils.sol | 6 +-- contracts/proxy/beacon/BeaconProxy.sol | 6 +-- contracts/proxy/beacon/UpgradeableBeacon.sol | 4 +- contracts/proxy/transparent/ProxyAdmin.sol | 4 +- .../TransparentUpgradeableProxy.sol | 5 ++- contracts/proxy/utils/Initializable.sol | 2 +- contracts/proxy/utils/UUPSUpgradeable.sol | 4 +- contracts/security/Pausable.sol | 2 +- contracts/token/ERC1155/ERC1155.sol | 14 +++---- contracts/token/ERC1155/IERC1155.sol | 2 +- contracts/token/ERC1155/IERC1155Receiver.sol | 2 +- .../ERC1155/extensions/ERC1155Burnable.sol | 2 +- .../ERC1155/extensions/ERC1155Pausable.sol | 4 +- .../ERC1155/extensions/ERC1155Supply.sol | 2 +- .../ERC1155/extensions/ERC1155URIStorage.sol | 4 +- .../extensions/IERC1155MetadataURI.sol | 2 +- .../token/ERC1155/utils/ERC1155Holder.sol | 2 +- .../token/ERC1155/utils/ERC1155Receiver.sol | 4 +- contracts/token/ERC20/ERC20.sol | 8 ++-- .../token/ERC20/extensions/ERC20Burnable.sol | 4 +- .../token/ERC20/extensions/ERC20Capped.sol | 2 +- .../token/ERC20/extensions/ERC20FlashMint.sol | 6 +-- .../token/ERC20/extensions/ERC20Pausable.sol | 4 +- .../token/ERC20/extensions/ERC20Permit.sol | 10 ++--- .../token/ERC20/extensions/ERC20Votes.sol | 7 ++-- .../token/ERC20/extensions/ERC20Wrapper.sol | 4 +- contracts/token/ERC20/extensions/ERC4626.sol | 8 ++-- .../token/ERC20/extensions/IERC20Metadata.sol | 2 +- contracts/token/ERC20/utils/SafeERC20.sol | 6 +-- contracts/token/ERC721/ERC721.sol | 14 +++---- contracts/token/ERC721/IERC721.sol | 2 +- .../ERC721/extensions/ERC721Burnable.sol | 4 +- .../ERC721/extensions/ERC721Consecutive.sol | 8 ++-- .../ERC721/extensions/ERC721Enumerable.sol | 5 ++- .../ERC721/extensions/ERC721Pausable.sol | 4 +- .../token/ERC721/extensions/ERC721Royalty.sol | 6 +-- .../ERC721/extensions/ERC721URIStorage.sol | 6 ++- .../token/ERC721/extensions/ERC721Votes.sol | 4 +- .../token/ERC721/extensions/ERC721Wrapper.sol | 3 +- .../ERC721/extensions/IERC721Enumerable.sol | 2 +- .../ERC721/extensions/IERC721Metadata.sol | 2 +- contracts/token/ERC721/utils/ERC721Holder.sol | 2 +- contracts/token/common/ERC2981.sol | 4 +- contracts/utils/Arrays.sol | 4 +- contracts/utils/Multicall.sol | 2 +- contracts/utils/ShortStrings.sol | 2 +- contracts/utils/Strings.sol | 4 +- contracts/utils/cryptography/ECDSA.sol | 2 +- contracts/utils/cryptography/EIP712.sol | 6 +-- .../utils/cryptography/SignatureChecker.sol | 4 +- contracts/utils/introspection/ERC165.sol | 2 +- .../utils/introspection/ERC165Checker.sol | 2 +- contracts/utils/structs/Checkpoints.sol | 4 +- contracts/utils/structs/DoubleEndedQueue.sol | 2 +- contracts/utils/structs/EnumerableMap.sol | 2 +- docs/modules/ROOT/pages/access-control.adoc | 14 +++---- docs/modules/ROOT/pages/erc1155.adoc | 4 +- docs/modules/ROOT/pages/erc20.adoc | 2 +- docs/modules/ROOT/pages/erc721.adoc | 2 +- .../ROOT/pages/extending-contracts.adoc | 6 +-- docs/modules/ROOT/pages/governance.adoc | 12 +++--- docs/modules/ROOT/pages/index.adoc | 2 +- docs/modules/ROOT/pages/upgradeable.adoc | 4 +- docs/modules/ROOT/pages/utilities.adoc | 6 +-- package-lock.json | 14 +++---- package.json | 2 +- scripts/generate/templates/Checkpoints.js | 6 +-- scripts/generate/templates/Checkpoints.t.js | 6 +-- scripts/generate/templates/EnumerableMap.js | 2 +- scripts/upgradeable/upgradeable.patch | 38 +++++++++---------- test/governance/Governor.t.sol | 6 +-- .../ERC721/extensions/ERC721Consecutive.t.sol | 5 ++- test/utils/ShortStrings.t.sol | 4 +- test/utils/math/Math.t.sol | 4 +- test/utils/structs/Checkpoints.t.sol | 6 +-- 176 files changed, 428 insertions(+), 379 deletions(-) create mode 100644 .changeset/orange-apes-draw.md diff --git a/.changeset/orange-apes-draw.md b/.changeset/orange-apes-draw.md new file mode 100644 index 000000000..5f2b7d928 --- /dev/null +++ b/.changeset/orange-apes-draw.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': major +--- + +Switched to using explicit Solidity import statements. Some previously available symbols may now have to be separately imported. diff --git a/.solhint.json b/.solhint.json index 772928849..cb8a8af6d 100644 --- a/.solhint.json +++ b/.solhint.json @@ -9,6 +9,7 @@ "modifier-name-mixedcase": "error", "private-vars-leading-underscore": "error", "var-name-mixedcase": "error", - "imports-on-top": "error" + "imports-on-top": "error", + "no-global-import": "error" } } diff --git a/README.md b/README.md index 9d1c405b6..27627f439 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Once installed, you can use the contracts in the library by importing them: ```solidity pragma solidity ^0.8.19; -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract MyCollectible is ERC721 { constructor() ERC721("MyCollectible", "MCO") { diff --git a/contracts/access/AccessControl.sol b/contracts/access/AccessControl.sol index 12dc770b3..8465fefbd 100644 --- a/contracts/access/AccessControl.sol +++ b/contracts/access/AccessControl.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.19; -import "./IAccessControl.sol"; -import "../utils/Context.sol"; -import "../utils/Strings.sol"; -import "../utils/introspection/ERC165.sol"; +import {IAccessControl} from "./IAccessControl.sol"; +import {Context} from "../utils/Context.sol"; +import {Strings} from "../utils/Strings.sol"; +import {ERC165} from "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access diff --git a/contracts/access/AccessControlDefaultAdminRules.sol b/contracts/access/AccessControlDefaultAdminRules.sol index e27eaf3db..ebc40a5bf 100644 --- a/contracts/access/AccessControlDefaultAdminRules.sol +++ b/contracts/access/AccessControlDefaultAdminRules.sol @@ -3,10 +3,11 @@ pragma solidity ^0.8.19; -import "./AccessControl.sol"; -import "./IAccessControlDefaultAdminRules.sol"; -import "../utils/math/SafeCast.sol"; -import "../interfaces/IERC5313.sol"; +import {AccessControl, IAccessControl} from "./AccessControl.sol"; +import {IAccessControlDefaultAdminRules} from "./IAccessControlDefaultAdminRules.sol"; +import {SafeCast} from "../utils/math/SafeCast.sol"; +import {Math} from "../utils/math/Math.sol"; +import {IERC5313} from "../interfaces/IERC5313.sol"; /** * @dev Extension of {AccessControl} that allows specifying special rules to manage diff --git a/contracts/access/AccessControlEnumerable.sol b/contracts/access/AccessControlEnumerable.sol index 297d34536..6f160e4e8 100644 --- a/contracts/access/AccessControlEnumerable.sol +++ b/contracts/access/AccessControlEnumerable.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; -import "./IAccessControlEnumerable.sol"; -import "./AccessControl.sol"; -import "../utils/structs/EnumerableSet.sol"; +import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol"; +import {AccessControl} from "./AccessControl.sol"; +import {EnumerableSet} from "../utils/structs/EnumerableSet.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. diff --git a/contracts/access/IAccessControlDefaultAdminRules.sol b/contracts/access/IAccessControlDefaultAdminRules.sol index fbecfe120..5e61f965d 100644 --- a/contracts/access/IAccessControlDefaultAdminRules.sol +++ b/contracts/access/IAccessControlDefaultAdminRules.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./IAccessControl.sol"; +import {IAccessControl} from "./IAccessControl.sol"; /** * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection. diff --git a/contracts/access/IAccessControlEnumerable.sol b/contracts/access/IAccessControlEnumerable.sol index 240c61157..1bd88a4f4 100644 --- a/contracts/access/IAccessControlEnumerable.sol +++ b/contracts/access/IAccessControlEnumerable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./IAccessControl.sol"; +import {IAccessControl} from "./IAccessControl.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. diff --git a/contracts/access/Ownable.sol b/contracts/access/Ownable.sol index 627226cf7..ca09e0350 100644 --- a/contracts/access/Ownable.sol +++ b/contracts/access/Ownable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../utils/Context.sol"; +import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where diff --git a/contracts/access/Ownable2Step.sol b/contracts/access/Ownable2Step.sol index f76eb2bba..3cbab1798 100644 --- a/contracts/access/Ownable2Step.sol +++ b/contracts/access/Ownable2Step.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./Ownable.sol"; +import {Ownable} from "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where diff --git a/contracts/finance/VestingWallet.sol b/contracts/finance/VestingWallet.sol index ebdf0a330..f776a7ca4 100644 --- a/contracts/finance/VestingWallet.sol +++ b/contracts/finance/VestingWallet.sol @@ -2,9 +2,10 @@ // OpenZeppelin Contracts (last updated v4.9.0) (finance/VestingWallet.sol) pragma solidity ^0.8.19; -import "../token/ERC20/utils/SafeERC20.sol"; -import "../utils/Address.sol"; -import "../utils/Context.sol"; +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol"; +import {Address} from "../utils/Address.sol"; +import {Context} from "../utils/Context.sol"; /** * @title VestingWallet diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index bae5d62e6..d0ace4f03 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -3,16 +3,16 @@ pragma solidity ^0.8.19; -import "../token/ERC721/IERC721Receiver.sol"; -import "../token/ERC1155/IERC1155Receiver.sol"; -import "../utils/cryptography/ECDSA.sol"; -import "../utils/cryptography/EIP712.sol"; -import "../utils/introspection/ERC165.sol"; -import "../utils/math/SafeCast.sol"; -import "../utils/structs/DoubleEndedQueue.sol"; -import "../utils/Address.sol"; -import "../utils/Context.sol"; -import "./IGovernor.sol"; +import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; +import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; +import {IERC165, ERC165} from "../utils/introspection/ERC165.sol"; +import {SafeCast} from "../utils/math/SafeCast.sol"; +import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; +import {Address} from "../utils/Address.sol"; +import {Context} from "../utils/Context.sol"; +import {IGovernor, IERC6372} from "./IGovernor.sol"; /** * @dev Core of the governance system, designed to be extended though various modules. diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index 0adde6795..2eeedd313 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../interfaces/IERC165.sol"; -import "../interfaces/IERC6372.sol"; +import {IERC165} from "../interfaces/IERC165.sol"; +import {IERC6372} from "../interfaces/IERC6372.sol"; /** * @dev Interface of the {Governor} core. diff --git a/contracts/governance/TimelockController.sol b/contracts/governance/TimelockController.sol index a25cd7b4a..45d8642e8 100644 --- a/contracts/governance/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -3,10 +3,11 @@ pragma solidity ^0.8.19; -import "../access/AccessControl.sol"; -import "../token/ERC721/utils/ERC721Holder.sol"; -import "../token/ERC1155/utils/ERC1155Holder.sol"; -import "../utils/Address.sol"; +import {AccessControl} from "../access/AccessControl.sol"; +import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC1155Receiver} from "../token/ERC1155/utils/ERC1155Receiver.sol"; +import {Address} from "../utils/Address.sol"; /** * @dev Contract module which acts as a timelocked controller. When set as the diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 8d6d9ccb4..445f71be0 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.19; -import "../../utils/math/SafeCast.sol"; -import "../extensions/IGovernorTimelock.sol"; -import "../Governor.sol"; -import "./IGovernorCompatibilityBravo.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {IGovernorTimelock} from "../extensions/IGovernorTimelock.sol"; +import {IGovernor, Governor} from "../Governor.sol"; +import {IGovernorCompatibilityBravo} from "./IGovernorCompatibilityBravo.sol"; /** * @dev Compatibility layer that implements GovernorBravo compatibility on top of {Governor}. diff --git a/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol b/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol index 197936ab9..4bd593077 100644 --- a/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../IGovernor.sol"; +import {IGovernor} from "../IGovernor.sol"; /** * @dev Interface extension that adds missing functions to the {Governor} core to provide `GovernorBravo` compatibility. diff --git a/contracts/governance/extensions/GovernorCountingSimple.sol b/contracts/governance/extensions/GovernorCountingSimple.sol index 315f4ad45..8934995de 100644 --- a/contracts/governance/extensions/GovernorCountingSimple.sol +++ b/contracts/governance/extensions/GovernorCountingSimple.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../Governor.sol"; +import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} for simple, 3 options, vote counting. diff --git a/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/contracts/governance/extensions/GovernorPreventLateQuorum.sol index 3e730174e..3e034acad 100644 --- a/contracts/governance/extensions/GovernorPreventLateQuorum.sol +++ b/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../Governor.sol"; -import "../../utils/math/Math.sol"; +import {Governor} from "../Governor.sol"; +import {Math} from "../../utils/math/Math.sol"; /** * @dev A module that ensures there is a minimum voting period after quorum is reached. This prevents a large voter from diff --git a/contracts/governance/extensions/GovernorSettings.sol b/contracts/governance/extensions/GovernorSettings.sol index 6168689ad..5d98fbf34 100644 --- a/contracts/governance/extensions/GovernorSettings.sol +++ b/contracts/governance/extensions/GovernorSettings.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../Governor.sol"; +import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} for settings updatable through governance. diff --git a/contracts/governance/extensions/GovernorTimelockCompound.sol b/contracts/governance/extensions/GovernorTimelockCompound.sol index ed4d916a6..cd61d1ff8 100644 --- a/contracts/governance/extensions/GovernorTimelockCompound.sol +++ b/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -3,10 +3,12 @@ pragma solidity ^0.8.19; -import "./IGovernorTimelock.sol"; -import "../Governor.sol"; -import "../../utils/math/SafeCast.sol"; -import "../../vendor/compound/ICompoundTimelock.sol"; +import {IGovernorTimelock} from "./IGovernorTimelock.sol"; +import {IGovernor, Governor} from "../Governor.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {ICompoundTimelock} from "../../vendor/compound/ICompoundTimelock.sol"; +import {IERC165} from "../../interfaces/IERC165.sol"; +import {Address} from "../../utils/Address.sol"; /** * @dev Extension of {Governor} that binds the execution process to a Compound Timelock. This adds a delay, enforced by diff --git a/contracts/governance/extensions/GovernorTimelockControl.sol b/contracts/governance/extensions/GovernorTimelockControl.sol index fadbcc701..fefe31555 100644 --- a/contracts/governance/extensions/GovernorTimelockControl.sol +++ b/contracts/governance/extensions/GovernorTimelockControl.sol @@ -3,9 +3,10 @@ pragma solidity ^0.8.19; -import "./IGovernorTimelock.sol"; -import "../Governor.sol"; -import "../TimelockController.sol"; +import {IGovernorTimelock} from "./IGovernorTimelock.sol"; +import {IGovernor, Governor} from "../Governor.sol"; +import {TimelockController} from "../TimelockController.sol"; +import {IERC165} from "../../interfaces/IERC165.sol"; /** * @dev Extension of {Governor} that binds the execution process to an instance of {TimelockController}. This adds a diff --git a/contracts/governance/extensions/GovernorVotes.sol b/contracts/governance/extensions/GovernorVotes.sol index 5d8318f46..bb14d7fde 100644 --- a/contracts/governance/extensions/GovernorVotes.sol +++ b/contracts/governance/extensions/GovernorVotes.sol @@ -3,8 +3,10 @@ pragma solidity ^0.8.19; -import "../Governor.sol"; -import "../../interfaces/IERC5805.sol"; +import {Governor} from "../Governor.sol"; +import {IVotes} from "../utils/IVotes.sol"; +import {IERC5805} from "../../interfaces/IERC5805.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} token. diff --git a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol index 0094fecd6..bb1c7d2ea 100644 --- a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol +++ b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; -import "./GovernorVotes.sol"; -import "../../utils/math/SafeCast.sol"; -import "../../utils/structs/Checkpoints.sol"; +import {GovernorVotes} from "./GovernorVotes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a diff --git a/contracts/governance/extensions/IGovernorTimelock.sol b/contracts/governance/extensions/IGovernorTimelock.sol index c51429481..00254853a 100644 --- a/contracts/governance/extensions/IGovernorTimelock.sol +++ b/contracts/governance/extensions/IGovernorTimelock.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../IGovernor.sol"; +import {IGovernor} from "../IGovernor.sol"; /** * @dev Extension of the {IGovernor} for timelock supporting modules. diff --git a/contracts/governance/utils/Votes.sol b/contracts/governance/utils/Votes.sol index 09eb4e22c..c0ff69e62 100644 --- a/contracts/governance/utils/Votes.sol +++ b/contracts/governance/utils/Votes.sol @@ -2,11 +2,13 @@ // OpenZeppelin Contracts (last updated v4.9.0) (governance/utils/Votes.sol) pragma solidity ^0.8.19; -import "../../interfaces/IERC5805.sol"; -import "../../utils/Context.sol"; -import "../../utils/Nonces.sol"; -import "../../utils/cryptography/EIP712.sol"; -import "../../utils/structs/Checkpoints.sol"; +import {IERC5805} from "../../interfaces/IERC5805.sol"; +import {Context} from "../../utils/Context.sol"; +import {Nonces} from "../../utils/Nonces.sol"; +import {EIP712} from "../../utils/cryptography/EIP712.sol"; +import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {ECDSA} from "../../utils/cryptography/ECDSA.sol"; /** * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be diff --git a/contracts/interfaces/IERC1155.sol b/contracts/interfaces/IERC1155.sol index 8f7527f91..6c9ef7f6c 100644 --- a/contracts/interfaces/IERC1155.sol +++ b/contracts/interfaces/IERC1155.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC1155/IERC1155.sol"; +import {IERC1155} from "../token/ERC1155/IERC1155.sol"; diff --git a/contracts/interfaces/IERC1155MetadataURI.sol b/contracts/interfaces/IERC1155MetadataURI.sol index 61b36c2e8..7c202be48 100644 --- a/contracts/interfaces/IERC1155MetadataURI.sol +++ b/contracts/interfaces/IERC1155MetadataURI.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC1155/extensions/IERC1155MetadataURI.sol"; +import {IERC1155MetadataURI} from "../token/ERC1155/extensions/IERC1155MetadataURI.sol"; diff --git a/contracts/interfaces/IERC1155Receiver.sol b/contracts/interfaces/IERC1155Receiver.sol index b5cd186b7..c67ed38bd 100644 --- a/contracts/interfaces/IERC1155Receiver.sol +++ b/contracts/interfaces/IERC1155Receiver.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC1155/IERC1155Receiver.sol"; +import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; diff --git a/contracts/interfaces/IERC1363.sol b/contracts/interfaces/IERC1363.sol index 95c5b8992..2bbba32b6 100644 --- a/contracts/interfaces/IERC1363.sol +++ b/contracts/interfaces/IERC1363.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "./IERC20.sol"; -import "./IERC165.sol"; +import {IERC20} from "./IERC20.sol"; +import {IERC165} from "./IERC165.sol"; /** * @dev Interface of an ERC1363 compliant contract, as defined in the diff --git a/contracts/interfaces/IERC165.sol b/contracts/interfaces/IERC165.sol index f4d90264c..3ac6e69dd 100644 --- a/contracts/interfaces/IERC165.sol +++ b/contracts/interfaces/IERC165.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../utils/introspection/IERC165.sol"; +import {IERC165} from "../utils/introspection/IERC165.sol"; diff --git a/contracts/interfaces/IERC20.sol b/contracts/interfaces/IERC20.sol index dd559e980..3ff660480 100644 --- a/contracts/interfaces/IERC20.sol +++ b/contracts/interfaces/IERC20.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC20/IERC20.sol"; +import {IERC20} from "../token/ERC20/IERC20.sol"; diff --git a/contracts/interfaces/IERC20Metadata.sol b/contracts/interfaces/IERC20Metadata.sol index 061fd4a2f..edb680446 100644 --- a/contracts/interfaces/IERC20Metadata.sol +++ b/contracts/interfaces/IERC20Metadata.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC20/extensions/IERC20Metadata.sol"; +import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/contracts/interfaces/IERC2612.sol b/contracts/interfaces/IERC2612.sol index 582eea81d..3a1b35266 100644 --- a/contracts/interfaces/IERC2612.sol +++ b/contracts/interfaces/IERC2612.sol @@ -3,6 +3,6 @@ pragma solidity ^0.8.19; -import "../token/ERC20/extensions/IERC20Permit.sol"; +import {IERC20Permit} from "../token/ERC20/extensions/IERC20Permit.sol"; interface IERC2612 is IERC20Permit {} diff --git a/contracts/interfaces/IERC2981.sol b/contracts/interfaces/IERC2981.sol index 1b1476782..ba0f98c99 100644 --- a/contracts/interfaces/IERC2981.sol +++ b/contracts/interfaces/IERC2981.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../utils/introspection/IERC165.sol"; +import {IERC165} from "../utils/introspection/IERC165.sol"; /** * @dev Interface for the NFT Royalty Standard. diff --git a/contracts/interfaces/IERC3156.sol b/contracts/interfaces/IERC3156.sol index 280b25be1..6bd56088b 100644 --- a/contracts/interfaces/IERC3156.sol +++ b/contracts/interfaces/IERC3156.sol @@ -3,5 +3,5 @@ pragma solidity ^0.8.19; -import "./IERC3156FlashBorrower.sol"; -import "./IERC3156FlashLender.sol"; +import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "./IERC3156FlashLender.sol"; diff --git a/contracts/interfaces/IERC3156FlashLender.sol b/contracts/interfaces/IERC3156FlashLender.sol index 89a486fdb..e5dd9c523 100644 --- a/contracts/interfaces/IERC3156FlashLender.sol +++ b/contracts/interfaces/IERC3156FlashLender.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./IERC3156FlashBorrower.sol"; +import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; /** * @dev Interface of the ERC3156 FlashLender, as defined in diff --git a/contracts/interfaces/IERC4626.sol b/contracts/interfaces/IERC4626.sol index 946de9155..27735f6b9 100644 --- a/contracts/interfaces/IERC4626.sol +++ b/contracts/interfaces/IERC4626.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../token/ERC20/IERC20.sol"; -import "../token/ERC20/extensions/IERC20Metadata.sol"; +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in diff --git a/contracts/interfaces/IERC4906.sol b/contracts/interfaces/IERC4906.sol index 96e709228..fecdb0c52 100644 --- a/contracts/interfaces/IERC4906.sol +++ b/contracts/interfaces/IERC4906.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "./IERC165.sol"; -import "./IERC721.sol"; +import {IERC165} from "./IERC165.sol"; +import {IERC721} from "./IERC721.sol"; /// @title EIP-721 Metadata Update Extension interface IERC4906 is IERC165, IERC721 { diff --git a/contracts/interfaces/IERC5805.sol b/contracts/interfaces/IERC5805.sol index 3c0a3a6c6..6eb89919f 100644 --- a/contracts/interfaces/IERC5805.sol +++ b/contracts/interfaces/IERC5805.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../governance/utils/IVotes.sol"; -import "./IERC6372.sol"; +import {IVotes} from "../governance/utils/IVotes.sol"; +import {IERC6372} from "./IERC6372.sol"; interface IERC5805 is IERC6372, IVotes {} diff --git a/contracts/interfaces/IERC721.sol b/contracts/interfaces/IERC721.sol index e840f28c7..f086ab6fb 100644 --- a/contracts/interfaces/IERC721.sol +++ b/contracts/interfaces/IERC721.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC721/IERC721.sol"; +import {IERC721} from "../token/ERC721/IERC721.sol"; diff --git a/contracts/interfaces/IERC721Enumerable.sol b/contracts/interfaces/IERC721Enumerable.sol index fafda5998..e5ce68d99 100644 --- a/contracts/interfaces/IERC721Enumerable.sol +++ b/contracts/interfaces/IERC721Enumerable.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC721/extensions/IERC721Enumerable.sol"; +import {IERC721Enumerable} from "../token/ERC721/extensions/IERC721Enumerable.sol"; diff --git a/contracts/interfaces/IERC721Metadata.sol b/contracts/interfaces/IERC721Metadata.sol index f14433e8d..5b2ad5687 100644 --- a/contracts/interfaces/IERC721Metadata.sol +++ b/contracts/interfaces/IERC721Metadata.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC721/extensions/IERC721Metadata.sol"; +import {IERC721Metadata} from "../token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/contracts/interfaces/IERC721Receiver.sol b/contracts/interfaces/IERC721Receiver.sol index 9e62fa734..6ee3d3d80 100644 --- a/contracts/interfaces/IERC721Receiver.sol +++ b/contracts/interfaces/IERC721Receiver.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.19; -import "../token/ERC721/IERC721Receiver.sol"; +import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; diff --git a/contracts/metatx/ERC2771Context.sol b/contracts/metatx/ERC2771Context.sol index e02ffcc19..35de9f7ba 100644 --- a/contracts/metatx/ERC2771Context.sol +++ b/contracts/metatx/ERC2771Context.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../utils/Context.sol"; +import {Context} from "../utils/Context.sol"; /** * @dev Context variant with ERC2771 support. diff --git a/contracts/metatx/ERC2771Forwarder.sol b/contracts/metatx/ERC2771Forwarder.sol index 651fdce0b..290b438b8 100644 --- a/contracts/metatx/ERC2771Forwarder.sol +++ b/contracts/metatx/ERC2771Forwarder.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.19; -import "../utils/cryptography/ECDSA.sol"; -import "../utils/cryptography/EIP712.sol"; -import "../utils/Nonces.sol"; -import "../utils/Address.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; +import {Nonces} from "../utils/Nonces.sol"; +import {Address} from "../utils/Address.sol"; /** * @dev A forwarder compatible with ERC2771 contracts. See {ERC2771Context}. diff --git a/contracts/mocks/AddressFnPointersMock.sol b/contracts/mocks/AddressFnPointersMock.sol index c696b3ec1..9d16a5263 100644 --- a/contracts/mocks/AddressFnPointersMock.sol +++ b/contracts/mocks/AddressFnPointersMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../utils/Address.sol"; +import {Address} from "../utils/Address.sol"; /** * @dev A mock to expose `Address`'s functions with function pointers. diff --git a/contracts/mocks/ArraysMock.sol b/contracts/mocks/ArraysMock.sol index b341edc62..7c049b7df 100644 --- a/contracts/mocks/ArraysMock.sol +++ b/contracts/mocks/ArraysMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../utils/Arrays.sol"; +import {Arrays} from "../utils/Arrays.sol"; contract Uint256ArraysMock { using Arrays for uint256[]; diff --git a/contracts/mocks/ContextMock.sol b/contracts/mocks/ContextMock.sol index 2e7751d0e..fd105aa91 100644 --- a/contracts/mocks/ContextMock.sol +++ b/contracts/mocks/ContextMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../utils/Context.sol"; +import {Context} from "../utils/Context.sol"; contract ContextMock is Context { event Sender(address sender); diff --git a/contracts/mocks/DummyImplementation.sol b/contracts/mocks/DummyImplementation.sol index 71761a755..4d3254602 100644 --- a/contracts/mocks/DummyImplementation.sol +++ b/contracts/mocks/DummyImplementation.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.19; -import "../proxy/ERC1967/ERC1967Utils.sol"; +import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; abstract contract Impl { function version() public pure virtual returns (string memory); diff --git a/contracts/mocks/EIP712Verifier.sol b/contracts/mocks/EIP712Verifier.sol index ea28162ba..91a1150f6 100644 --- a/contracts/mocks/EIP712Verifier.sol +++ b/contracts/mocks/EIP712Verifier.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.19; -import "../utils/cryptography/ECDSA.sol"; -import "../utils/cryptography/EIP712.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; abstract contract EIP712Verifier is EIP712 { function verify(bytes memory signature, address signer, address mailTo, string memory mailContents) external view { diff --git a/contracts/mocks/ERC1271WalletMock.sol b/contracts/mocks/ERC1271WalletMock.sol index 2bc390636..e142fe73e 100644 --- a/contracts/mocks/ERC1271WalletMock.sol +++ b/contracts/mocks/ERC1271WalletMock.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.19; -import "../access/Ownable.sol"; -import "../interfaces/IERC1271.sol"; -import "../utils/cryptography/ECDSA.sol"; +import {Ownable} from "../access/Ownable.sol"; +import {IERC1271} from "../interfaces/IERC1271.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; contract ERC1271WalletMock is Ownable, IERC1271 { constructor(address originalOwner) Ownable(originalOwner) {} diff --git a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol index d21d7c2d0..c9a1df485 100644 --- a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol +++ b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../utils/introspection/IERC165.sol"; +import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * https://eips.ethereum.org/EIPS/eip-214#specification diff --git a/contracts/mocks/ERC165/ERC165ReturnBomb.sol b/contracts/mocks/ERC165/ERC165ReturnBomb.sol index d2a64151f..99f4685cf 100644 --- a/contracts/mocks/ERC165/ERC165ReturnBomb.sol +++ b/contracts/mocks/ERC165/ERC165ReturnBomb.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../utils/introspection/IERC165.sol"; +import {IERC165} from "../../utils/introspection/IERC165.sol"; contract ERC165ReturnBombMock is IERC165 { function supportsInterface(bytes4 interfaceId) public pure override returns (bool) { diff --git a/contracts/mocks/ERC2771ContextMock.sol b/contracts/mocks/ERC2771ContextMock.sol index 8c2cb43fd..3cdc211d8 100644 --- a/contracts/mocks/ERC2771ContextMock.sol +++ b/contracts/mocks/ERC2771ContextMock.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.19; -import "./ContextMock.sol"; -import "../metatx/ERC2771Context.sol"; +import {ContextMock} from "./ContextMock.sol"; +import {Context} from "../utils/Context.sol"; +import {ERC2771Context} from "../metatx/ERC2771Context.sol"; // By inheriting from ERC2771Context, Context's internal functions are overridden automatically contract ERC2771ContextMock is ContextMock, ERC2771Context { diff --git a/contracts/mocks/ERC3156FlashBorrowerMock.sol b/contracts/mocks/ERC3156FlashBorrowerMock.sol index abf836606..c426a7ef7 100644 --- a/contracts/mocks/ERC3156FlashBorrowerMock.sol +++ b/contracts/mocks/ERC3156FlashBorrowerMock.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.19; -import "../token/ERC20/IERC20.sol"; -import "../interfaces/IERC3156.sol"; -import "../utils/Address.sol"; +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {IERC3156FlashBorrower} from "../interfaces/IERC3156.sol"; +import {Address} from "../utils/Address.sol"; /** * @dev WARNING: this IERC3156FlashBorrower mock implementation is for testing purposes ONLY. diff --git a/contracts/mocks/InitializableMock.sol b/contracts/mocks/InitializableMock.sol index 513aac052..155aaefb7 100644 --- a/contracts/mocks/InitializableMock.sol +++ b/contracts/mocks/InitializableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../proxy/utils/Initializable.sol"; +import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @title InitializableMock diff --git a/contracts/mocks/MulticallTest.sol b/contracts/mocks/MulticallTest.sol index cf89c58df..89a18b3c9 100644 --- a/contracts/mocks/MulticallTest.sol +++ b/contracts/mocks/MulticallTest.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "./token/ERC20MulticallMock.sol"; +import {ERC20MulticallMock} from "./token/ERC20MulticallMock.sol"; contract MulticallTest { function checkReturnValues( diff --git a/contracts/mocks/MultipleInheritanceInitializableMocks.sol b/contracts/mocks/MultipleInheritanceInitializableMocks.sol index cb62942ce..d5982f0e3 100644 --- a/contracts/mocks/MultipleInheritanceInitializableMocks.sol +++ b/contracts/mocks/MultipleInheritanceInitializableMocks.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../proxy/utils/Initializable.sol"; +import {Initializable} from "../proxy/utils/Initializable.sol"; // Sample contracts showing upgradeability with multiple inheritance. // Child contract inherits from Father and Mother contracts, and Father extends from Gramps. diff --git a/contracts/mocks/PausableMock.sol b/contracts/mocks/PausableMock.sol index 85d45a3af..56bd4f45f 100644 --- a/contracts/mocks/PausableMock.sol +++ b/contracts/mocks/PausableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../security/Pausable.sol"; +import {Pausable} from "../security/Pausable.sol"; contract PausableMock is Pausable { bool public drasticMeasureTaken; diff --git a/contracts/mocks/ReentrancyAttack.sol b/contracts/mocks/ReentrancyAttack.sol index df2924301..d0ba74c31 100644 --- a/contracts/mocks/ReentrancyAttack.sol +++ b/contracts/mocks/ReentrancyAttack.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../utils/Context.sol"; +import {Context} from "../utils/Context.sol"; contract ReentrancyAttack is Context { function callSender(bytes calldata data) public { diff --git a/contracts/mocks/ReentrancyMock.sol b/contracts/mocks/ReentrancyMock.sol index 053e53d77..1754c1557 100644 --- a/contracts/mocks/ReentrancyMock.sol +++ b/contracts/mocks/ReentrancyMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.19; -import "../security/ReentrancyGuard.sol"; -import "./ReentrancyAttack.sol"; +import {ReentrancyGuard} from "../security/ReentrancyGuard.sol"; +import {ReentrancyAttack} from "./ReentrancyAttack.sol"; contract ReentrancyMock is ReentrancyGuard { uint256 public counter; diff --git a/contracts/mocks/RegressionImplementation.sol b/contracts/mocks/RegressionImplementation.sol index f258bbc0e..bfcf52c44 100644 --- a/contracts/mocks/RegressionImplementation.sol +++ b/contracts/mocks/RegressionImplementation.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../proxy/utils/Initializable.sol"; +import {Initializable} from "../proxy/utils/Initializable.sol"; contract Implementation1 is Initializable { uint256 internal _value; diff --git a/contracts/mocks/SingleInheritanceInitializableMocks.sol b/contracts/mocks/SingleInheritanceInitializableMocks.sol index 2b5fad4eb..d755826d9 100644 --- a/contracts/mocks/SingleInheritanceInitializableMocks.sol +++ b/contracts/mocks/SingleInheritanceInitializableMocks.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../proxy/utils/Initializable.sol"; +import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @title MigratableMockV1 diff --git a/contracts/mocks/StorageSlotMock.sol b/contracts/mocks/StorageSlotMock.sol index 62dd23d6a..7bbd7b232 100644 --- a/contracts/mocks/StorageSlotMock.sol +++ b/contracts/mocks/StorageSlotMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../utils/StorageSlot.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; contract StorageSlotMock { using StorageSlot for *; diff --git a/contracts/mocks/TimelockReentrant.sol b/contracts/mocks/TimelockReentrant.sol index 803a2b037..de55a87f3 100644 --- a/contracts/mocks/TimelockReentrant.sol +++ b/contracts/mocks/TimelockReentrant.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../utils/Address.sol"; +import {Address} from "../utils/Address.sol"; contract TimelockReentrant { address private _reenterTarget; diff --git a/contracts/mocks/VotesMock.sol b/contracts/mocks/VotesMock.sol index 697d33448..0bac0087c 100644 --- a/contracts/mocks/VotesMock.sol +++ b/contracts/mocks/VotesMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../governance/utils/Votes.sol"; +import {Votes} from "../governance/utils/Votes.sol"; abstract contract VotesMock is Votes { mapping(address => uint256) private _votingUnits; diff --git a/contracts/mocks/docs/ERC4626Fees.sol b/contracts/mocks/docs/ERC4626Fees.sol index 703e4245a..c82279a60 100644 --- a/contracts/mocks/docs/ERC4626Fees.sol +++ b/contracts/mocks/docs/ERC4626Fees.sol @@ -2,7 +2,10 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/extensions/ERC4626.sol"; +import {IERC20} from "../../token/ERC20/IERC20.sol"; +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; +import {SafeERC20} from "../../token/ERC20/utils/SafeERC20.sol"; +import {Math} from "../../utils/math/Math.sol"; abstract contract ERC4626Fees is ERC4626 { using Math for uint256; diff --git a/contracts/mocks/docs/governance/MyGovernor.sol b/contracts/mocks/docs/governance/MyGovernor.sol index 095523b3d..f788f04a6 100644 --- a/contracts/mocks/docs/governance/MyGovernor.sol +++ b/contracts/mocks/docs/governance/MyGovernor.sol @@ -1,11 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -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 {IGovernor, Governor} from "../../../governance/Governor.sol"; +import {GovernorCompatibilityBravo} from "../../../governance/compatibility/GovernorCompatibilityBravo.sol"; +import {GovernorVotes} from "../../../governance/extensions/GovernorVotes.sol"; +import {GovernorVotesQuorumFraction} from "../../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import {GovernorTimelockControl} from "../../../governance/extensions/GovernorTimelockControl.sol"; +import {TimelockController} from "../../../governance/TimelockController.sol"; +import {IVotes} from "../../../governance/utils/IVotes.sol"; +import {IERC165} from "../../../interfaces/IERC165.sol"; contract MyGovernor is Governor, diff --git a/contracts/mocks/docs/governance/MyToken.sol b/contracts/mocks/docs/governance/MyToken.sol index f7707ff9d..7a700212b 100644 --- a/contracts/mocks/docs/governance/MyToken.sol +++ b/contracts/mocks/docs/governance/MyToken.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../../../token/ERC20/ERC20.sol"; -import "../../../token/ERC20/extensions/ERC20Permit.sol"; -import "../../../token/ERC20/extensions/ERC20Votes.sol"; +import {ERC20} from "../../../token/ERC20/ERC20.sol"; +import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; contract MyToken is ERC20, ERC20Permit, ERC20Votes { constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {} diff --git a/contracts/mocks/docs/governance/MyTokenTimestampBased.sol b/contracts/mocks/docs/governance/MyTokenTimestampBased.sol index 1c688c250..100d10f51 100644 --- a/contracts/mocks/docs/governance/MyTokenTimestampBased.sol +++ b/contracts/mocks/docs/governance/MyTokenTimestampBased.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../../../token/ERC20/ERC20.sol"; -import "../../../token/ERC20/extensions/ERC20Permit.sol"; -import "../../../token/ERC20/extensions/ERC20Votes.sol"; +import {ERC20} from "../../../token/ERC20/ERC20.sol"; +import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; contract MyTokenTimestampBased is ERC20, ERC20Permit, ERC20Votes { constructor() ERC20("MyTokenTimestampBased", "MTK") ERC20Permit("MyTokenTimestampBased") {} diff --git a/contracts/mocks/docs/governance/MyTokenWrapped.sol b/contracts/mocks/docs/governance/MyTokenWrapped.sol index 6637dccc3..94182187a 100644 --- a/contracts/mocks/docs/governance/MyTokenWrapped.sol +++ b/contracts/mocks/docs/governance/MyTokenWrapped.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../../../token/ERC20/ERC20.sol"; -import "../../../token/ERC20/extensions/ERC20Permit.sol"; -import "../../../token/ERC20/extensions/ERC20Votes.sol"; -import "../../../token/ERC20/extensions/ERC20Wrapper.sol"; +import {IERC20, ERC20} from "../../../token/ERC20/ERC20.sol"; +import {ERC20Permit} from "../../../token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Votes} from "../../../token/ERC20/extensions/ERC20Votes.sol"; +import {ERC20Wrapper} from "../../../token/ERC20/extensions/ERC20Wrapper.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; contract MyTokenWrapped is ERC20, ERC20Permit, ERC20Votes, ERC20Wrapper { constructor( diff --git a/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol b/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol index 6e14a357d..516dd8ff2 100644 --- a/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol +++ b/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol @@ -2,10 +2,12 @@ pragma solidity ^0.8.19; -import "../../governance/compatibility/GovernorCompatibilityBravo.sol"; -import "../../governance/extensions/GovernorTimelockCompound.sol"; -import "../../governance/extensions/GovernorSettings.sol"; -import "../../governance/extensions/GovernorVotes.sol"; +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorCompatibilityBravo} from "../../governance/compatibility/GovernorCompatibilityBravo.sol"; +import {IGovernorTimelock, GovernorTimelockCompound} from "../../governance/extensions/GovernorTimelockCompound.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; +import {IERC165} from "../../interfaces/IERC165.sol"; abstract contract GovernorCompatibilityBravoMock is GovernorCompatibilityBravo, diff --git a/contracts/mocks/governance/GovernorMock.sol b/contracts/mocks/governance/GovernorMock.sol index 9104c3f32..64024b2ce 100644 --- a/contracts/mocks/governance/GovernorMock.sol +++ b/contracts/mocks/governance/GovernorMock.sol @@ -2,9 +2,10 @@ pragma solidity ^0.8.19; -import "../../governance/extensions/GovernorSettings.sol"; -import "../../governance/extensions/GovernorCountingSimple.sol"; -import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import {Governor} from "../../governance/Governor.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; abstract contract GovernorMock is GovernorSettings, GovernorVotesQuorumFraction, GovernorCountingSimple { function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { diff --git a/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol b/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol index 4c1b408e6..785e5df5c 100644 --- a/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol +++ b/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.19; -import "../../governance/extensions/GovernorPreventLateQuorum.sol"; -import "../../governance/extensions/GovernorSettings.sol"; -import "../../governance/extensions/GovernorCountingSimple.sol"; -import "../../governance/extensions/GovernorVotes.sol"; +import {Governor} from "../../governance/Governor.sol"; +import {GovernorPreventLateQuorum} from "../../governance/extensions/GovernorPreventLateQuorum.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; abstract contract GovernorPreventLateQuorumMock is GovernorSettings, diff --git a/contracts/mocks/governance/GovernorTimelockCompoundMock.sol b/contracts/mocks/governance/GovernorTimelockCompoundMock.sol index 134d66133..102dffae8 100644 --- a/contracts/mocks/governance/GovernorTimelockCompoundMock.sol +++ b/contracts/mocks/governance/GovernorTimelockCompoundMock.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.19; -import "../../governance/extensions/GovernorTimelockCompound.sol"; -import "../../governance/extensions/GovernorSettings.sol"; -import "../../governance/extensions/GovernorCountingSimple.sol"; -import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockCompound} from "../../governance/extensions/GovernorTimelockCompound.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; abstract contract GovernorTimelockCompoundMock is GovernorSettings, diff --git a/contracts/mocks/governance/GovernorTimelockControlMock.sol b/contracts/mocks/governance/GovernorTimelockControlMock.sol index 28376835a..5c83acd64 100644 --- a/contracts/mocks/governance/GovernorTimelockControlMock.sol +++ b/contracts/mocks/governance/GovernorTimelockControlMock.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.19; -import "../../governance/extensions/GovernorTimelockControl.sol"; -import "../../governance/extensions/GovernorSettings.sol"; -import "../../governance/extensions/GovernorCountingSimple.sol"; -import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockControl} from "../../governance/extensions/GovernorTimelockControl.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; abstract contract GovernorTimelockControlMock is GovernorSettings, diff --git a/contracts/mocks/governance/GovernorVoteMock.sol b/contracts/mocks/governance/GovernorVoteMock.sol index 1d0722ecf..ecb80a4fb 100644 --- a/contracts/mocks/governance/GovernorVoteMock.sol +++ b/contracts/mocks/governance/GovernorVoteMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.19; -import "../../governance/extensions/GovernorCountingSimple.sol"; -import "../../governance/extensions/GovernorVotes.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; abstract contract GovernorVoteMocks is GovernorVotes, GovernorCountingSimple { function quorum(uint256) public pure override returns (uint256) { diff --git a/contracts/mocks/governance/GovernorWithParamsMock.sol b/contracts/mocks/governance/GovernorWithParamsMock.sol index f8de83710..f67bd4b71 100644 --- a/contracts/mocks/governance/GovernorWithParamsMock.sol +++ b/contracts/mocks/governance/GovernorWithParamsMock.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.19; -import "../../governance/extensions/GovernorCountingSimple.sol"; -import "../../governance/extensions/GovernorVotes.sol"; +import {Governor} from "../../governance/Governor.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; abstract contract GovernorWithParamsMock is GovernorVotes, GovernorCountingSimple { event CountParams(uint256 uintParam, string strParam); diff --git a/contracts/mocks/proxy/UUPSUpgradeableMock.sol b/contracts/mocks/proxy/UUPSUpgradeableMock.sol index 77744998b..4333e63e8 100644 --- a/contracts/mocks/proxy/UUPSUpgradeableMock.sol +++ b/contracts/mocks/proxy/UUPSUpgradeableMock.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.19; -import "../../proxy/utils/UUPSUpgradeable.sol"; +import {UUPSUpgradeable} from "../../proxy/utils/UUPSUpgradeable.sol"; +import {ERC1967Utils} from "../../proxy/ERC1967/ERC1967Utils.sol"; contract NonUpgradeableMock { uint256 internal _counter; diff --git a/contracts/mocks/token/ERC1155ReceiverMock.sol b/contracts/mocks/token/ERC1155ReceiverMock.sol index a5d7233cf..b02617333 100644 --- a/contracts/mocks/token/ERC1155ReceiverMock.sol +++ b/contracts/mocks/token/ERC1155ReceiverMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.19; -import "../../token/ERC1155/IERC1155Receiver.sol"; -import "../../utils/introspection/ERC165.sol"; +import {IERC1155Receiver} from "../../token/ERC1155/IERC1155Receiver.sol"; +import {ERC165} from "../../utils/introspection/ERC165.sol"; contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { enum RevertType { diff --git a/contracts/mocks/token/ERC20ApprovalMock.sol b/contracts/mocks/token/ERC20ApprovalMock.sol index da8f51e1e..3caa7d0d2 100644 --- a/contracts/mocks/token/ERC20ApprovalMock.sol +++ b/contracts/mocks/token/ERC20ApprovalMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; abstract contract ERC20ApprovalMock is ERC20 { function _approve(address owner, address spender, uint256 amount, bool) internal virtual override { diff --git a/contracts/mocks/token/ERC20DecimalsMock.sol b/contracts/mocks/token/ERC20DecimalsMock.sol index 5699d31d2..3ecc77f4e 100644 --- a/contracts/mocks/token/ERC20DecimalsMock.sol +++ b/contracts/mocks/token/ERC20DecimalsMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; abstract contract ERC20DecimalsMock is ERC20 { uint8 private immutable _decimals; diff --git a/contracts/mocks/token/ERC20FlashMintMock.sol b/contracts/mocks/token/ERC20FlashMintMock.sol index 05c4db57d..1831f53bd 100644 --- a/contracts/mocks/token/ERC20FlashMintMock.sol +++ b/contracts/mocks/token/ERC20FlashMintMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/extensions/ERC20FlashMint.sol"; +import {ERC20FlashMint} from "../../token/ERC20/extensions/ERC20FlashMint.sol"; abstract contract ERC20FlashMintMock is ERC20FlashMint { uint256 _flashFeeAmount; diff --git a/contracts/mocks/token/ERC20ForceApproveMock.sol b/contracts/mocks/token/ERC20ForceApproveMock.sol index 42b417f41..f6f71a7e8 100644 --- a/contracts/mocks/token/ERC20ForceApproveMock.sol +++ b/contracts/mocks/token/ERC20ForceApproveMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; // contract that replicate USDT (0xdac17f958d2ee523a2206206994597c13d831ec7) approval beavior abstract contract ERC20ForceApproveMock is ERC20 { diff --git a/contracts/mocks/token/ERC20Mock.sol b/contracts/mocks/token/ERC20Mock.sol index 5fb134f60..cd5f9d444 100644 --- a/contracts/mocks/token/ERC20Mock.sol +++ b/contracts/mocks/token/ERC20Mock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; contract ERC20Mock is ERC20 { constructor() ERC20("ERC20Mock", "E20M") {} diff --git a/contracts/mocks/token/ERC20MulticallMock.sol b/contracts/mocks/token/ERC20MulticallMock.sol index b8259a75a..87aaf8923 100644 --- a/contracts/mocks/token/ERC20MulticallMock.sol +++ b/contracts/mocks/token/ERC20MulticallMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; -import "../../utils/Multicall.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; +import {Multicall} from "../../utils/Multicall.sol"; abstract contract ERC20MulticallMock is ERC20, Multicall {} diff --git a/contracts/mocks/token/ERC20NoReturnMock.sol b/contracts/mocks/token/ERC20NoReturnMock.sol index 7d597ad89..e7f234cff 100644 --- a/contracts/mocks/token/ERC20NoReturnMock.sol +++ b/contracts/mocks/token/ERC20NoReturnMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; abstract contract ERC20NoReturnMock is ERC20 { function transfer(address to, uint256 amount) public override returns (bool) { diff --git a/contracts/mocks/token/ERC20PermitNoRevertMock.sol b/contracts/mocks/token/ERC20PermitNoRevertMock.sol index 510176cf5..23395d75d 100644 --- a/contracts/mocks/token/ERC20PermitNoRevertMock.sol +++ b/contracts/mocks/token/ERC20PermitNoRevertMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; -import "../../token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; +import {ERC20Permit} from "../../token/ERC20/extensions/ERC20Permit.sol"; abstract contract ERC20PermitNoRevertMock is ERC20Permit { function permitThatMayRevert( diff --git a/contracts/mocks/token/ERC20Reentrant.sol b/contracts/mocks/token/ERC20Reentrant.sol index 00ba74260..063e9f3d5 100644 --- a/contracts/mocks/token/ERC20Reentrant.sol +++ b/contracts/mocks/token/ERC20Reentrant.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; -import "../../utils/Address.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; +import {Address} from "../../utils/Address.sol"; contract ERC20Reentrant is ERC20("TEST", "TST") { enum Type { diff --git a/contracts/mocks/token/ERC20ReturnFalseMock.sol b/contracts/mocks/token/ERC20ReturnFalseMock.sol index 763a120e9..e8014b87b 100644 --- a/contracts/mocks/token/ERC20ReturnFalseMock.sol +++ b/contracts/mocks/token/ERC20ReturnFalseMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/ERC20.sol"; +import {ERC20} from "../../token/ERC20/ERC20.sol"; abstract contract ERC20ReturnFalseMock is ERC20 { function transfer(address, uint256) public pure override returns (bool) { diff --git a/contracts/mocks/token/ERC20VotesLegacyMock.sol b/contracts/mocks/token/ERC20VotesLegacyMock.sol index 88ba84236..6a2078510 100644 --- a/contracts/mocks/token/ERC20VotesLegacyMock.sol +++ b/contracts/mocks/token/ERC20VotesLegacyMock.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/extensions/ERC20Permit.sol"; -import "../../utils/math/Math.sol"; -import "../../governance/utils/IVotes.sol"; -import "../../utils/math/SafeCast.sol"; -import "../../utils/cryptography/ECDSA.sol"; +import {ERC20Permit} from "../../token/ERC20/extensions/ERC20Permit.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {IVotes} from "../../governance/utils/IVotes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {ECDSA} from "../../utils/cryptography/ECDSA.sol"; /** * @dev Copied from the master branch at commit 86de1e8b6c3fa6b4efa4a5435869d2521be0f5f5 diff --git a/contracts/mocks/token/ERC4626LimitsMock.sol b/contracts/mocks/token/ERC4626LimitsMock.sol index a47826bb8..fe5d724c8 100644 --- a/contracts/mocks/token/ERC4626LimitsMock.sol +++ b/contracts/mocks/token/ERC4626LimitsMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/extensions/ERC4626.sol"; +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; abstract contract ERC4626LimitsMock is ERC4626 { uint256 _maxDeposit; diff --git a/contracts/mocks/token/ERC4626Mock.sol b/contracts/mocks/token/ERC4626Mock.sol index 3713e0791..151606ca5 100644 --- a/contracts/mocks/token/ERC4626Mock.sol +++ b/contracts/mocks/token/ERC4626Mock.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../../token/ERC20/extensions/ERC4626.sol"; +import {IERC20, ERC20} from "../../token/ERC20/ERC20.sol"; +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; contract ERC4626Mock is ERC4626 { constructor(address underlying) ERC20("ERC4626Mock", "E4626M") ERC4626(IERC20(underlying)) {} diff --git a/contracts/mocks/token/ERC4626OffsetMock.sol b/contracts/mocks/token/ERC4626OffsetMock.sol index b3c31cdd2..b1dac7d5d 100644 --- a/contracts/mocks/token/ERC4626OffsetMock.sol +++ b/contracts/mocks/token/ERC4626OffsetMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/extensions/ERC4626.sol"; +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; abstract contract ERC4626OffsetMock is ERC4626 { uint8 private immutable _offset; diff --git a/contracts/mocks/token/ERC4646FeesMock.sol b/contracts/mocks/token/ERC4646FeesMock.sol index 4c6c3c662..f8fde293c 100644 --- a/contracts/mocks/token/ERC4646FeesMock.sol +++ b/contracts/mocks/token/ERC4646FeesMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../docs/ERC4626Fees.sol"; +import {ERC4626Fees} from "../docs/ERC4626Fees.sol"; abstract contract ERC4626FeesMock is ERC4626Fees { uint256 private immutable _entryFeeBasePointValue; diff --git a/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol b/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol index a2ee8199a..081b8d99d 100644 --- a/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol +++ b/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.19; -import "../../token/ERC721/extensions/ERC721Consecutive.sol"; -import "../../token/ERC721/extensions/ERC721Enumerable.sol"; +import {ERC721} from "../../token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import {ERC721Enumerable} from "../../token/ERC721/extensions/ERC721Enumerable.sol"; contract ERC721ConsecutiveEnumerableMock is ERC721Consecutive, ERC721Enumerable { constructor( diff --git a/contracts/mocks/token/ERC721ConsecutiveMock.sol b/contracts/mocks/token/ERC721ConsecutiveMock.sol index 4aae388e0..166959e92 100644 --- a/contracts/mocks/token/ERC721ConsecutiveMock.sol +++ b/contracts/mocks/token/ERC721ConsecutiveMock.sol @@ -2,9 +2,11 @@ pragma solidity ^0.8.19; -import "../../token/ERC721/extensions/ERC721Consecutive.sol"; -import "../../token/ERC721/extensions/ERC721Pausable.sol"; -import "../../token/ERC721/extensions/ERC721Votes.sol"; +import {ERC721} from "../../token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import {ERC721Pausable} from "../../token/ERC721/extensions/ERC721Pausable.sol"; +import {ERC721Votes} from "../../token/ERC721/extensions/ERC721Votes.sol"; +import {EIP712} from "../../utils/cryptography/EIP712.sol"; /** * @title ERC721ConsecutiveMock diff --git a/contracts/mocks/token/ERC721ReceiverMock.sol b/contracts/mocks/token/ERC721ReceiverMock.sol index 416613174..f1c842e49 100644 --- a/contracts/mocks/token/ERC721ReceiverMock.sol +++ b/contracts/mocks/token/ERC721ReceiverMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC721/IERC721Receiver.sol"; +import {IERC721Receiver} from "../../token/ERC721/IERC721Receiver.sol"; contract ERC721ReceiverMock is IERC721Receiver { enum RevertType { diff --git a/contracts/mocks/token/ERC721URIStorageMock.sol b/contracts/mocks/token/ERC721URIStorageMock.sol index 1808e47f7..569a1c0f4 100644 --- a/contracts/mocks/token/ERC721URIStorageMock.sol +++ b/contracts/mocks/token/ERC721URIStorageMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import "../../token/ERC721/extensions/ERC721URIStorage.sol"; +import {ERC721URIStorage} from "../../token/ERC721/extensions/ERC721URIStorage.sol"; abstract contract ERC721URIStorageMock is ERC721URIStorage { string private _baseTokenURI; diff --git a/contracts/mocks/token/VotesTimestamp.sol b/contracts/mocks/token/VotesTimestamp.sol index 7e3d8ca6d..b54dbda97 100644 --- a/contracts/mocks/token/VotesTimestamp.sol +++ b/contracts/mocks/token/VotesTimestamp.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.19; -import "../../token/ERC20/extensions/ERC20Votes.sol"; -import "../../token/ERC721/extensions/ERC721Votes.sol"; +import {ERC20Votes} from "../../token/ERC20/extensions/ERC20Votes.sol"; +import {ERC721Votes} from "../../token/ERC721/extensions/ERC721Votes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; abstract contract ERC20VotesTimestampMock is ERC20Votes { function clock() public view virtual override returns (uint48) { diff --git a/contracts/proxy/ERC1967/ERC1967Proxy.sol b/contracts/proxy/ERC1967/ERC1967Proxy.sol index 5a752f13d..e7c90c706 100644 --- a/contracts/proxy/ERC1967/ERC1967Proxy.sol +++ b/contracts/proxy/ERC1967/ERC1967Proxy.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../Proxy.sol"; -import "./ERC1967Utils.sol"; +import {Proxy} from "../Proxy.sol"; +import {ERC1967Utils} from "./ERC1967Utils.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an diff --git a/contracts/proxy/ERC1967/ERC1967Utils.sol b/contracts/proxy/ERC1967/ERC1967Utils.sol index c244982bf..843fa6584 100644 --- a/contracts/proxy/ERC1967/ERC1967Utils.sol +++ b/contracts/proxy/ERC1967/ERC1967Utils.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.20; -import "../beacon/IBeacon.sol"; -import "../../utils/Address.sol"; -import "../../utils/StorageSlot.sol"; +import {IBeacon} from "../beacon/IBeacon.sol"; +import {Address} from "../../utils/Address.sol"; +import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for diff --git a/contracts/proxy/beacon/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol index dc6b5c90b..57883b692 100644 --- a/contracts/proxy/beacon/BeaconProxy.sol +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; -import "./IBeacon.sol"; -import "../Proxy.sol"; -import "../ERC1967/ERC1967Utils.sol"; +import {IBeacon} from "./IBeacon.sol"; +import {Proxy} from "../Proxy.sol"; +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; /** * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. diff --git a/contracts/proxy/beacon/UpgradeableBeacon.sol b/contracts/proxy/beacon/UpgradeableBeacon.sol index c5e64ea59..0c72ddf63 100644 --- a/contracts/proxy/beacon/UpgradeableBeacon.sol +++ b/contracts/proxy/beacon/UpgradeableBeacon.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "./IBeacon.sol"; -import "../../access/Ownable.sol"; +import {IBeacon} from "./IBeacon.sol"; +import {Ownable} from "../../access/Ownable.sol"; /** * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their diff --git a/contracts/proxy/transparent/ProxyAdmin.sol b/contracts/proxy/transparent/ProxyAdmin.sol index e8578a585..344c942f2 100644 --- a/contracts/proxy/transparent/ProxyAdmin.sol +++ b/contracts/proxy/transparent/ProxyAdmin.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "./TransparentUpgradeableProxy.sol"; -import "../../access/Ownable.sol"; +import {ITransparentUpgradeableProxy, TransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol"; +import {Ownable} from "../../access/Ownable.sol"; /** * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an diff --git a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol index 71ce665d0..3d6e11f38 100644 --- a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +++ b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -3,8 +3,9 @@ pragma solidity ^0.8.19; -import "../ERC1967/ERC1967Proxy.sol"; -import "../../interfaces/IERC1967.sol"; +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; +import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol"; +import {IERC1967} from "../../interfaces/IERC1967.sol"; /** * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy} diff --git a/contracts/proxy/utils/Initializable.sol b/contracts/proxy/utils/Initializable.sol index 3ae5e4a65..86e99531b 100644 --- a/contracts/proxy/utils/Initializable.sol +++ b/contracts/proxy/utils/Initializable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../../utils/Address.sol"; +import {Address} from "../../utils/Address.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed diff --git a/contracts/proxy/utils/UUPSUpgradeable.sol b/contracts/proxy/utils/UUPSUpgradeable.sol index 07de178bc..7d1515bbb 100644 --- a/contracts/proxy/utils/UUPSUpgradeable.sol +++ b/contracts/proxy/utils/UUPSUpgradeable.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../../interfaces/draft-IERC1822.sol"; -import "../ERC1967/ERC1967Utils.sol"; +import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol"; +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an diff --git a/contracts/security/Pausable.sol b/contracts/security/Pausable.sol index dc0afa663..7a54b2511 100644 --- a/contracts/security/Pausable.sol +++ b/contracts/security/Pausable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../utils/Context.sol"; +import {Context} from "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop diff --git a/contracts/token/ERC1155/ERC1155.sol b/contracts/token/ERC1155/ERC1155.sol index e4bd74826..9d70714fa 100644 --- a/contracts/token/ERC1155/ERC1155.sol +++ b/contracts/token/ERC1155/ERC1155.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.19; -import "./IERC1155.sol"; -import "./IERC1155Receiver.sol"; -import "./extensions/IERC1155MetadataURI.sol"; -import "../../utils/Context.sol"; -import "../../utils/introspection/ERC165.sol"; -import "../../utils/Arrays.sol"; -import "../../interfaces/draft-IERC6093.sol"; +import {IERC1155} from "./IERC1155.sol"; +import {IERC1155Receiver} from "./IERC1155Receiver.sol"; +import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol"; +import {Context} from "../../utils/Context.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; +import {Arrays} from "../../utils/Arrays.sol"; +import {IERC1155Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev Implementation of the basic standard multi-token. diff --git a/contracts/token/ERC1155/IERC1155.sol b/contracts/token/ERC1155/IERC1155.sol index 16b2b71a3..c450eec2f 100644 --- a/contracts/token/ERC1155/IERC1155.sol +++ b/contracts/token/ERC1155/IERC1155.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../../utils/introspection/IERC165.sol"; +import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the diff --git a/contracts/token/ERC1155/IERC1155Receiver.sol b/contracts/token/ERC1155/IERC1155Receiver.sol index a272f61b0..04ef783f1 100644 --- a/contracts/token/ERC1155/IERC1155Receiver.sol +++ b/contracts/token/ERC1155/IERC1155Receiver.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../../utils/introspection/IERC165.sol"; +import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev _Available since v3.1._ diff --git a/contracts/token/ERC1155/extensions/ERC1155Burnable.sol b/contracts/token/ERC1155/extensions/ERC1155Burnable.sol index d7bee05d9..5ebfcf6c4 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Burnable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Burnable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../ERC1155.sol"; +import {ERC1155} from "../ERC1155.sol"; /** * @dev Extension of {ERC1155} that allows token holders to destroy both their diff --git a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol index f8357062c..05aa8a780 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../ERC1155.sol"; -import "../../../security/Pausable.sol"; +import {ERC1155} from "../ERC1155.sol"; +import {Pausable} from "../../../security/Pausable.sol"; /** * @dev ERC1155 token with pausable token transfers, minting and burning. diff --git a/contracts/token/ERC1155/extensions/ERC1155Supply.sol b/contracts/token/ERC1155/extensions/ERC1155Supply.sol index f32fbb74b..eefa0ebf7 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Supply.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Supply.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../ERC1155.sol"; +import {ERC1155} from "../ERC1155.sol"; /** * @dev Extension of ERC1155 that adds tracking of total supply per id. diff --git a/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol b/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol index 79782a42b..303b452b8 100644 --- a/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol +++ b/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../../../utils/Strings.sol"; -import "../ERC1155.sol"; +import {Strings} from "../../../utils/Strings.sol"; +import {ERC1155} from "../ERC1155.sol"; /** * @dev ERC1155 token with storage based token URI management. diff --git a/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol b/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol index 2c998995e..88462ef87 100644 --- a/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol +++ b/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../IERC1155.sol"; +import {IERC1155} from "../IERC1155.sol"; /** * @dev Interface of the optional ERC1155MetadataExtension interface, as defined diff --git a/contracts/token/ERC1155/utils/ERC1155Holder.sol b/contracts/token/ERC1155/utils/ERC1155Holder.sol index d24a1a53a..87c42b02f 100644 --- a/contracts/token/ERC1155/utils/ERC1155Holder.sol +++ b/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./ERC1155Receiver.sol"; +import {ERC1155Receiver} from "./ERC1155Receiver.sol"; /** * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. diff --git a/contracts/token/ERC1155/utils/ERC1155Receiver.sol b/contracts/token/ERC1155/utils/ERC1155Receiver.sol index 6fb21491f..cf948ced7 100644 --- a/contracts/token/ERC1155/utils/ERC1155Receiver.sol +++ b/contracts/token/ERC1155/utils/ERC1155Receiver.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../IERC1155Receiver.sol"; -import "../../../utils/introspection/ERC165.sol"; +import {IERC1155Receiver} from "../IERC1155Receiver.sol"; +import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; /** * @dev _Available since v3.1._ diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index 5ddebf22b..d43880da6 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.19; -import "./IERC20.sol"; -import "./extensions/IERC20Metadata.sol"; -import "../../utils/Context.sol"; -import "../../interfaces/draft-IERC6093.sol"; +import {IERC20} from "./IERC20.sol"; +import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; +import {Context} from "../../utils/Context.sol"; +import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev Implementation of the {IERC20} interface. diff --git a/contracts/token/ERC20/extensions/ERC20Burnable.sol b/contracts/token/ERC20/extensions/ERC20Burnable.sol index cae186b64..2a6d28963 100644 --- a/contracts/token/ERC20/extensions/ERC20Burnable.sol +++ b/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../ERC20.sol"; -import "../../../utils/Context.sol"; +import {ERC20} from "../ERC20.sol"; +import {Context} from "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own diff --git a/contracts/token/ERC20/extensions/ERC20Capped.sol b/contracts/token/ERC20/extensions/ERC20Capped.sol index 41e9ce5cf..98ec71443 100644 --- a/contracts/token/ERC20/extensions/ERC20Capped.sol +++ b/contracts/token/ERC20/extensions/ERC20Capped.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../ERC20.sol"; +import {ERC20} from "../ERC20.sol"; /** * @dev Extension of {ERC20} that adds a cap to the supply of tokens. diff --git a/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/contracts/token/ERC20/extensions/ERC20FlashMint.sol index 09c20bacc..b63c75f71 100644 --- a/contracts/token/ERC20/extensions/ERC20FlashMint.sol +++ b/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; -import "../../../interfaces/IERC3156FlashBorrower.sol"; -import "../../../interfaces/IERC3156FlashLender.sol"; -import "../ERC20.sol"; +import {IERC3156FlashBorrower} from "../../../interfaces/IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "../../../interfaces/IERC3156FlashLender.sol"; +import {ERC20} from "../ERC20.sol"; /** * @dev Implementation of the ERC3156 Flash loans extension, as defined in diff --git a/contracts/token/ERC20/extensions/ERC20Pausable.sol b/contracts/token/ERC20/extensions/ERC20Pausable.sol index 5ef50f9c6..59f451639 100644 --- a/contracts/token/ERC20/extensions/ERC20Pausable.sol +++ b/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../ERC20.sol"; -import "../../../security/Pausable.sol"; +import {ERC20} from "../ERC20.sol"; +import {Pausable} from "../../../security/Pausable.sol"; /** * @dev ERC20 token with pausable token transfers, minting and burning. diff --git a/contracts/token/ERC20/extensions/ERC20Permit.sol b/contracts/token/ERC20/extensions/ERC20Permit.sol index 4378eb7c1..8778f4baf 100644 --- a/contracts/token/ERC20/extensions/ERC20Permit.sol +++ b/contracts/token/ERC20/extensions/ERC20Permit.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.19; -import "./IERC20Permit.sol"; -import "../ERC20.sol"; -import "../../../utils/cryptography/ECDSA.sol"; -import "../../../utils/cryptography/EIP712.sol"; -import "../../../utils/Nonces.sol"; +import {IERC20Permit} from "./IERC20Permit.sol"; +import {ERC20} from "../ERC20.sol"; +import {ECDSA} from "../../../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../../../utils/cryptography/EIP712.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in diff --git a/contracts/token/ERC20/extensions/ERC20Votes.sol b/contracts/token/ERC20/extensions/ERC20Votes.sol index 98f798efe..db5f71241 100644 --- a/contracts/token/ERC20/extensions/ERC20Votes.sol +++ b/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -3,9 +3,10 @@ pragma solidity ^0.8.19; -import "../ERC20.sol"; -import "../../../governance/utils/Votes.sol"; -import "../../../utils/math/SafeCast.sol"; +import {ERC20} from "../ERC20.sol"; +import {Votes} from "../../../governance/utils/Votes.sol"; +import {SafeCast} from "../../../utils/math/SafeCast.sol"; +import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; /** * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's, diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol index 389965e9c..2cbff6223 100644 --- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol +++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../ERC20.sol"; -import "../utils/SafeERC20.sol"; +import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol"; +import {SafeERC20} from "../utils/SafeERC20.sol"; /** * @dev Extension of the ERC20 token contract to support token wrapping. diff --git a/contracts/token/ERC20/extensions/ERC4626.sol b/contracts/token/ERC20/extensions/ERC4626.sol index 9ea6789f7..cb5e03da8 100644 --- a/contracts/token/ERC20/extensions/ERC4626.sol +++ b/contracts/token/ERC20/extensions/ERC4626.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.19; -import "../ERC20.sol"; -import "../utils/SafeERC20.sol"; -import "../../../interfaces/IERC4626.sol"; -import "../../../utils/math/Math.sol"; +import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol"; +import {SafeERC20} from "../utils/SafeERC20.sol"; +import {IERC4626} from "../../../interfaces/IERC4626.sol"; +import {Math} from "../../../utils/math/Math.sol"; /** * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in diff --git a/contracts/token/ERC20/extensions/IERC20Metadata.sol b/contracts/token/ERC20/extensions/IERC20Metadata.sol index 1cf7e0b2e..bdfe81145 100644 --- a/contracts/token/ERC20/extensions/IERC20Metadata.sol +++ b/contracts/token/ERC20/extensions/IERC20Metadata.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../IERC20.sol"; +import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. diff --git a/contracts/token/ERC20/utils/SafeERC20.sol b/contracts/token/ERC20/utils/SafeERC20.sol index 599307e7f..0ec21573b 100644 --- a/contracts/token/ERC20/utils/SafeERC20.sol +++ b/contracts/token/ERC20/utils/SafeERC20.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; -import "../IERC20.sol"; -import "../extensions/IERC20Permit.sol"; -import "../../../utils/Address.sol"; +import {IERC20} from "../IERC20.sol"; +import {IERC20Permit} from "../extensions/IERC20Permit.sol"; +import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index 21ed95813..4232c616e 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.19; -import "./IERC721.sol"; -import "./IERC721Receiver.sol"; -import "./extensions/IERC721Metadata.sol"; -import "../../utils/Context.sol"; -import "../../utils/Strings.sol"; -import "../../utils/introspection/ERC165.sol"; -import "../../interfaces/draft-IERC6093.sol"; +import {IERC721} from "./IERC721.sol"; +import {IERC721Receiver} from "./IERC721Receiver.sol"; +import {IERC721Metadata} from "./extensions/IERC721Metadata.sol"; +import {Context} from "../../utils/Context.sol"; +import {Strings} from "../../utils/Strings.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; +import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including diff --git a/contracts/token/ERC721/IERC721.sol b/contracts/token/ERC721/IERC721.sol index ba4c108ef..3b2db67cb 100644 --- a/contracts/token/ERC721/IERC721.sol +++ b/contracts/token/ERC721/IERC721.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../../utils/introspection/IERC165.sol"; +import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. diff --git a/contracts/token/ERC721/extensions/ERC721Burnable.sol b/contracts/token/ERC721/extensions/ERC721Burnable.sol index 217f039ca..607265328 100644 --- a/contracts/token/ERC721/extensions/ERC721Burnable.sol +++ b/contracts/token/ERC721/extensions/ERC721Burnable.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../ERC721.sol"; -import "../../../utils/Context.sol"; +import {ERC721} from "../ERC721.sol"; +import {Context} from "../../../utils/Context.sol"; /** * @title ERC721 Burnable Token diff --git a/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/contracts/token/ERC721/extensions/ERC721Consecutive.sol index f1308cdab..e25edfcd9 100644 --- a/contracts/token/ERC721/extensions/ERC721Consecutive.sol +++ b/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -3,10 +3,10 @@ pragma solidity ^0.8.19; -import "../ERC721.sol"; -import "../../../interfaces/IERC2309.sol"; -import "../../../utils/structs/BitMaps.sol"; -import "../../../utils/structs/Checkpoints.sol"; +import {ERC721} from "../ERC721.sol"; +import {IERC2309} from "../../../interfaces/IERC2309.sol"; +import {BitMaps} from "../../../utils/structs/BitMaps.sol"; +import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; /** * @dev Implementation of the ERC2309 "Consecutive Transfer Extension" as defined in diff --git a/contracts/token/ERC721/extensions/ERC721Enumerable.sol b/contracts/token/ERC721/extensions/ERC721Enumerable.sol index 18e2ba5d6..2e33123b6 100644 --- a/contracts/token/ERC721/extensions/ERC721Enumerable.sol +++ b/contracts/token/ERC721/extensions/ERC721Enumerable.sol @@ -3,8 +3,9 @@ pragma solidity ^0.8.19; -import "../ERC721.sol"; -import "./IERC721Enumerable.sol"; +import {ERC721} from "../ERC721.sol"; +import {IERC721Enumerable} from "./IERC721Enumerable.sol"; +import {IERC165} from "../../../utils/introspection/ERC165.sol"; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability diff --git a/contracts/token/ERC721/extensions/ERC721Pausable.sol b/contracts/token/ERC721/extensions/ERC721Pausable.sol index a9472c5dc..a4effc549 100644 --- a/contracts/token/ERC721/extensions/ERC721Pausable.sol +++ b/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../ERC721.sol"; -import "../../../security/Pausable.sol"; +import {ERC721} from "../ERC721.sol"; +import {Pausable} from "../../../security/Pausable.sol"; /** * @dev ERC721 token with pausable token transfers, minting and burning. diff --git a/contracts/token/ERC721/extensions/ERC721Royalty.sol b/contracts/token/ERC721/extensions/ERC721Royalty.sol index 7d6ef6c04..b4518dc24 100644 --- a/contracts/token/ERC721/extensions/ERC721Royalty.sol +++ b/contracts/token/ERC721/extensions/ERC721Royalty.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; -import "../ERC721.sol"; -import "../../common/ERC2981.sol"; -import "../../../utils/introspection/ERC165.sol"; +import {ERC721} from "../ERC721.sol"; +import {ERC2981} from "../../common/ERC2981.sol"; +import {ERC165} from "../../../utils/introspection/ERC165.sol"; /** * @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment diff --git a/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/contracts/token/ERC721/extensions/ERC721URIStorage.sol index ae625fc28..737d28e27 100644 --- a/contracts/token/ERC721/extensions/ERC721URIStorage.sol +++ b/contracts/token/ERC721/extensions/ERC721URIStorage.sol @@ -3,8 +3,10 @@ pragma solidity ^0.8.19; -import "../ERC721.sol"; -import "../../../interfaces/IERC4906.sol"; +import {ERC721} from "../ERC721.sol"; +import {Strings} from "../../../utils/Strings.sol"; +import {IERC4906} from "../../../interfaces/IERC4906.sol"; +import {IERC165} from "../../../interfaces/IERC165.sol"; /** * @dev ERC721 token with storage based token URI management. diff --git a/contracts/token/ERC721/extensions/ERC721Votes.sol b/contracts/token/ERC721/extensions/ERC721Votes.sol index 89b2e073c..1e694e4c7 100644 --- a/contracts/token/ERC721/extensions/ERC721Votes.sol +++ b/contracts/token/ERC721/extensions/ERC721Votes.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../ERC721.sol"; -import "../../../governance/utils/Votes.sol"; +import {ERC721} from "../ERC721.sol"; +import {Votes} from "../../../governance/utils/Votes.sol"; /** * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts diff --git a/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/contracts/token/ERC721/extensions/ERC721Wrapper.sol index 47a42c1f0..b8c396c3e 100644 --- a/contracts/token/ERC721/extensions/ERC721Wrapper.sol +++ b/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.19; -import "../ERC721.sol"; +import {IERC721, ERC721} from "../ERC721.sol"; +import {IERC721Receiver} from "../IERC721Receiver.sol"; /** * @dev Extension of the ERC721 token contract to support token wrapping. diff --git a/contracts/token/ERC721/extensions/IERC721Enumerable.sol b/contracts/token/ERC721/extensions/IERC721Enumerable.sol index d5fe6330c..75b04581f 100644 --- a/contracts/token/ERC721/extensions/IERC721Enumerable.sol +++ b/contracts/token/ERC721/extensions/IERC721Enumerable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../IERC721.sol"; +import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension diff --git a/contracts/token/ERC721/extensions/IERC721Metadata.sol b/contracts/token/ERC721/extensions/IERC721Metadata.sol index 0b085812c..3d2846231 100644 --- a/contracts/token/ERC721/extensions/IERC721Metadata.sol +++ b/contracts/token/ERC721/extensions/IERC721Metadata.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../IERC721.sol"; +import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension diff --git a/contracts/token/ERC721/utils/ERC721Holder.sol b/contracts/token/ERC721/utils/ERC721Holder.sol index a3ee8b5f0..e1fad1e23 100644 --- a/contracts/token/ERC721/utils/ERC721Holder.sol +++ b/contracts/token/ERC721/utils/ERC721Holder.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../IERC721Receiver.sol"; +import {IERC721Receiver} from "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. diff --git a/contracts/token/common/ERC2981.sol b/contracts/token/common/ERC2981.sol index 21869ee25..b9183e34e 100644 --- a/contracts/token/common/ERC2981.sol +++ b/contracts/token/common/ERC2981.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "../../interfaces/IERC2981.sol"; -import "../../utils/introspection/ERC165.sol"; +import {IERC2981} from "../../interfaces/IERC2981.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. diff --git a/contracts/utils/Arrays.sol b/contracts/utils/Arrays.sol index f4ef45645..7dbc86fdd 100644 --- a/contracts/utils/Arrays.sol +++ b/contracts/utils/Arrays.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "./StorageSlot.sol"; -import "./math/Math.sol"; +import {StorageSlot} from "./StorageSlot.sol"; +import {Math} from "./math/Math.sol"; /** * @dev Collection of functions related to array types. diff --git a/contracts/utils/Multicall.sol b/contracts/utils/Multicall.sol index 8e0ef8195..fed9844c4 100644 --- a/contracts/utils/Multicall.sol +++ b/contracts/utils/Multicall.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./Address.sol"; +import {Address} from "./Address.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. diff --git a/contracts/utils/ShortStrings.sol b/contracts/utils/ShortStrings.sol index a6cb1e620..f90ccd77a 100644 --- a/contracts/utils/ShortStrings.sol +++ b/contracts/utils/ShortStrings.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./StorageSlot.sol"; +import {StorageSlot} from "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | diff --git a/contracts/utils/Strings.sol b/contracts/utils/Strings.sol index afbf463d1..fd8d66229 100644 --- a/contracts/utils/Strings.sol +++ b/contracts/utils/Strings.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "./math/Math.sol"; -import "./math/SignedMath.sol"; +import {Math} from "./math/Math.sol"; +import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. diff --git a/contracts/utils/cryptography/ECDSA.sol b/contracts/utils/cryptography/ECDSA.sol index b8f1affee..5e67a7591 100644 --- a/contracts/utils/cryptography/ECDSA.sol +++ b/contracts/utils/cryptography/ECDSA.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "../Strings.sol"; +import {Strings} from "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol index 1089de005..d94e956af 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; -import "./ECDSA.sol"; -import "../ShortStrings.sol"; -import "../../interfaces/IERC5267.sol"; +import {ECDSA} from "./ECDSA.sol"; +import {ShortStrings, ShortString} from "../ShortStrings.sol"; +import {IERC5267} from "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. diff --git a/contracts/utils/cryptography/SignatureChecker.sol b/contracts/utils/cryptography/SignatureChecker.sol index 25fdee5b3..dfc512b39 100644 --- a/contracts/utils/cryptography/SignatureChecker.sol +++ b/contracts/utils/cryptography/SignatureChecker.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; -import "./ECDSA.sol"; -import "../../interfaces/IERC1271.sol"; +import {ECDSA} from "./ECDSA.sol"; +import {IERC1271} from "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA diff --git a/contracts/utils/introspection/ERC165.sol b/contracts/utils/introspection/ERC165.sol index 111913007..56fe1b80a 100644 --- a/contracts/utils/introspection/ERC165.sol +++ b/contracts/utils/introspection/ERC165.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./IERC165.sol"; +import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. diff --git a/contracts/utils/introspection/ERC165Checker.sol b/contracts/utils/introspection/ERC165Checker.sol index c27b2f17d..d614c6755 100644 --- a/contracts/utils/introspection/ERC165Checker.sol +++ b/contracts/utils/introspection/ERC165Checker.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; -import "./IERC165.sol"; +import {IERC165} from "./IERC165.sol"; /** * @dev Library used to query support of an interface declared via {IERC165}. diff --git a/contracts/utils/structs/Checkpoints.sol b/contracts/utils/structs/Checkpoints.sol index 7608d787e..47ad91bbf 100644 --- a/contracts/utils/structs/Checkpoints.sol +++ b/contracts/utils/structs/Checkpoints.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.19; -import "../math/Math.sol"; -import "../math/SafeCast.sol"; +import {Math} from "../math/Math.sol"; +import {SafeCast} from "../math/SafeCast.sol"; /** * @dev This library defines the `History` struct, for checkpointing values as they change at different points in diff --git a/contracts/utils/structs/DoubleEndedQueue.sol b/contracts/utils/structs/DoubleEndedQueue.sol index 69db70040..5183bad8c 100644 --- a/contracts/utils/structs/DoubleEndedQueue.sol +++ b/contracts/utils/structs/DoubleEndedQueue.sol @@ -2,7 +2,7 @@ // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/DoubleEndedQueue.sol) pragma solidity ^0.8.19; -import "../math/SafeCast.sol"; +import {SafeCast} from "../math/SafeCast.sol"; /** * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of diff --git a/contracts/utils/structs/EnumerableMap.sol b/contracts/utils/structs/EnumerableMap.sol index a474e82b3..c0ad9a2c9 100644 --- a/contracts/utils/structs/EnumerableMap.sol +++ b/contracts/utils/structs/EnumerableMap.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.19; -import "./EnumerableSet.sol"; +import {EnumerableSet} from "./EnumerableSet.sol"; /** * @dev Library for managing an enumerable variant of Solidity's diff --git a/docs/modules/ROOT/pages/access-control.adoc b/docs/modules/ROOT/pages/access-control.adoc index 11a5fab0c..aa28376ad 100644 --- a/docs/modules/ROOT/pages/access-control.adoc +++ b/docs/modules/ROOT/pages/access-control.adoc @@ -15,7 +15,7 @@ OpenZeppelin Contracts provides xref:api:access.adoc#Ownable[`Ownable`] for impl // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/access/Ownable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; contract MyContract is Ownable { function normalThing() public { @@ -64,8 +64,8 @@ Here's a simple example of using `AccessControl` in an xref:tokens.adoc#ERC20[`E // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/access/AccessControl.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20, AccessControl { // Create a new role identifier for the minter role @@ -96,8 +96,8 @@ Let's augment our ERC20 token example by also defining a 'burner' role, which le // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/access/AccessControl.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20, AccessControl { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); @@ -141,8 +141,8 @@ Let's take a look at the ERC20 token example, this time taking advantage of the // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/access/AccessControl.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20, AccessControl { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); diff --git a/docs/modules/ROOT/pages/erc1155.adoc b/docs/modules/ROOT/pages/erc1155.adoc index 067bde89e..f1d2f88ce 100644 --- a/docs/modules/ROOT/pages/erc1155.adoc +++ b/docs/modules/ROOT/pages/erc1155.adoc @@ -36,7 +36,7 @@ Here's what a contract for tokenized items might look like: // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; contract GameItems is ERC1155 { uint256 public constant GOLD = 0; @@ -136,7 +136,7 @@ In order for our contract to receive ERC1155 tokens we can inherit from the conv // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; contract MyContract is ERC1155Holder { } diff --git a/docs/modules/ROOT/pages/erc20.adoc b/docs/modules/ROOT/pages/erc20.adoc index 817d364b1..2ffa60f2a 100644 --- a/docs/modules/ROOT/pages/erc20.adoc +++ b/docs/modules/ROOT/pages/erc20.adoc @@ -17,7 +17,7 @@ Here's what our GLD token might look like. // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract GLDToken is ERC20 { constructor(uint256 initialSupply) ERC20("Gold", "GLD") { diff --git a/docs/modules/ROOT/pages/erc721.adoc b/docs/modules/ROOT/pages/erc721.adoc index 6d839c81e..cd4d14b8f 100644 --- a/docs/modules/ROOT/pages/erc721.adoc +++ b/docs/modules/ROOT/pages/erc721.adoc @@ -16,7 +16,7 @@ Here's what a contract for tokenized items might look like: // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; contract GameItem is ERC721URIStorage { uint256 private _nextTokenId; diff --git a/docs/modules/ROOT/pages/extending-contracts.adoc b/docs/modules/ROOT/pages/extending-contracts.adoc index df93f2133..ac6730984 100644 --- a/docs/modules/ROOT/pages/extending-contracts.adoc +++ b/docs/modules/ROOT/pages/extending-contracts.adoc @@ -22,7 +22,7 @@ For example, imagine you want to change xref:api:access.adoc#AccessControl[`Acce // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/access/AccessControl.sol"; +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; contract ModifiedAccessControl is AccessControl { // Override the revokeRole function @@ -50,7 +50,7 @@ Here is a modified version of xref:api:access.adoc#AccessControl[`AccessControl` // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/access/AccessControl.sol"; +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; contract ModifiedAccessControl is AccessControl { function revokeRole(bytes32 role, address account) public override { @@ -82,7 +82,7 @@ Here's how you would implement the `IERC721Receiver` pattern in `ERC20`, using t ```solidity pragma solidity ^0.8.19; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract ERC20WithSafeTransfer is ERC20 { function _beforeTokenTransfer(address from, address to, uint256 amount) diff --git a/docs/modules/ROOT/pages/governance.adoc b/docs/modules/ROOT/pages/governance.adoc index 3d2bc05f3..cae2f14f6 100644 --- a/docs/modules/ROOT/pages/governance.adoc +++ b/docs/modules/ROOT/pages/governance.adoc @@ -200,11 +200,12 @@ The Governor will automatically detect the clock mode used by the token and adap // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -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"; +import {Governor} from "@openzeppelin/contracts/governance/Governor.sol"; +import {GovernorCompatibilityBravo} from "@openzeppelin/contracts/governance/compatibility/GovernorCompatibilityBravo.sol"; +import {GovernorVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; +import {GovernorVotesQuorumFraction} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; +import {GovernorTimelockControl} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; +import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; contract MyGovernor is Governor, GovernorCompatibilityBravo, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl { constructor(IVotes _token, TimelockController _timelock) @@ -228,6 +229,7 @@ contract MyGovernor is Governor, GovernorCompatibilityBravo, GovernorVotes, Gove // ... } + ``` === Disclaimer diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index b46a8d5a3..b24412ae7 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -28,7 +28,7 @@ Once installed, you can use the contracts in the library by importing them: // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract MyNFT is ERC721 { constructor() ERC721("MyNFT", "MNFT") { diff --git a/docs/modules/ROOT/pages/upgradeable.adoc b/docs/modules/ROOT/pages/upgradeable.adoc index 2b8d27204..7324c9bad 100644 --- a/docs/modules/ROOT/pages/upgradeable.adoc +++ b/docs/modules/ROOT/pages/upgradeable.adoc @@ -21,8 +21,8 @@ $ npm install @openzeppelin/contracts-upgradeable The package replicates the structure of the main OpenZeppelin Contracts package, but every file and contract has the suffix `Upgradeable`. ```diff --import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -+import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +-import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; ++import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; -contract MyCollectible is ERC721 { +contract MyCollectible is ERC721Upgradeable { diff --git a/docs/modules/ROOT/pages/utilities.adoc b/docs/modules/ROOT/pages/utilities.adoc index 0b178d9fe..3a1ba5420 100644 --- a/docs/modules/ROOT/pages/utilities.adoc +++ b/docs/modules/ROOT/pages/utilities.adoc @@ -110,9 +110,9 @@ Here is an example to send JSON Metadata through a Base64 Data URI using an ERC7 // contracts/My721Token.sol // SPDX-License-Identifier: MIT -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import "@openzeppelin/contracts/utils/Strings.sol"; -import "@openzeppelin/contracts/utils/Base64.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {Base64} from "@openzeppelin/contracts/utils/Base64.sol"; contract My721Token is ERC721 { using Strings for uint256; diff --git a/package-lock.json b/package-lock.json index d4cb52694..a85611941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "glob": "^8.0.3", "graphlib": "^2.1.8", "hardhat": "^2.9.1", - "hardhat-exposed": "^0.3.3", + "hardhat-exposed": "^0.3.11", "hardhat-gas-reporter": "^1.0.4", "hardhat-ignore-warnings": "^0.2.0", "keccak256": "^1.0.2", @@ -7477,9 +7477,9 @@ } }, "node_modules/hardhat-exposed": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.6.tgz", - "integrity": "sha512-jb03M+GolhEfjDYJyPkGJzcAs1/eZrVufMADXQDwng2iuUJD1zgzM3k1oq2YQihRxguQDsLE1nuHIn6N8o5GmQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.11.tgz", + "integrity": "sha512-2Gwdfx1YpSWUX80kuq0zM1tNqDJoTBCd5Q5oXKPxz6STSy1TiDyDb1miUr4Dwc/Dp2lzWzM+fZjpUrMe5O08Hw==", "dev": true, "dependencies": { "micromatch": "^4.0.4", @@ -21420,9 +21420,9 @@ } }, "hardhat-exposed": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.6.tgz", - "integrity": "sha512-jb03M+GolhEfjDYJyPkGJzcAs1/eZrVufMADXQDwng2iuUJD1zgzM3k1oq2YQihRxguQDsLE1nuHIn6N8o5GmQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.11.tgz", + "integrity": "sha512-2Gwdfx1YpSWUX80kuq0zM1tNqDJoTBCd5Q5oXKPxz6STSy1TiDyDb1miUr4Dwc/Dp2lzWzM+fZjpUrMe5O08Hw==", "dev": true, "requires": { "micromatch": "^4.0.4", diff --git a/package.json b/package.json index 37e8f8710..9eae67320 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "glob": "^8.0.3", "graphlib": "^2.1.8", "hardhat": "^2.9.1", - "hardhat-exposed": "^0.3.3", + "hardhat-exposed": "^0.3.11", "hardhat-gas-reporter": "^1.0.4", "hardhat-ignore-warnings": "^0.2.0", "keccak256": "^1.0.2", diff --git a/scripts/generate/templates/Checkpoints.js b/scripts/generate/templates/Checkpoints.js index d28134ce7..d5ab745a0 100644 --- a/scripts/generate/templates/Checkpoints.js +++ b/scripts/generate/templates/Checkpoints.js @@ -5,8 +5,8 @@ const { OPTS } = require('./Checkpoints.opts.js'); const header = `\ pragma solidity ^0.8.19; -import "../math/Math.sol"; -import "../math/SafeCast.sol"; +import {Math} from "../math/Math.sol"; +import {SafeCast} from "../math/SafeCast.sol"; /** * @dev This library defines the \`History\` struct, for checkpointing values as they change at different points in @@ -21,7 +21,7 @@ import "../math/SafeCast.sol"; const errors = `\ /** - * @dev A value was attempted to be inserted on a past checkpoint. + * @dev A value was attempted to be inserted on a past checkpoint. */ error CheckpointUnorderedInsertion(); `; diff --git a/scripts/generate/templates/Checkpoints.t.js b/scripts/generate/templates/Checkpoints.t.js index c5b225f38..492e5f8c2 100644 --- a/scripts/generate/templates/Checkpoints.t.js +++ b/scripts/generate/templates/Checkpoints.t.js @@ -6,9 +6,9 @@ const { OPTS } = require('./Checkpoints.opts.js'); const header = `\ pragma solidity ^0.8.19; -import "forge-std/Test.sol"; -import "../../../contracts/utils/math/SafeCast.sol"; -import "../../../contracts/utils/structs/Checkpoints.sol"; +import {Test} from "forge-std/Test.sol"; +import {SafeCast} from "../../../contracts/utils/math/SafeCast.sol"; +import {Checkpoints} from "../../../contracts/utils/structs/Checkpoints.sol"; `; /* eslint-disable max-len */ diff --git a/scripts/generate/templates/EnumerableMap.js b/scripts/generate/templates/EnumerableMap.js index 8899f4819..032f08681 100644 --- a/scripts/generate/templates/EnumerableMap.js +++ b/scripts/generate/templates/EnumerableMap.js @@ -12,7 +12,7 @@ const TYPES = [ const header = `\ pragma solidity ^0.8.19; -import "./EnumerableSet.sol"; +import {EnumerableSet} from "./EnumerableSet.sol"; /** * @dev Library for managing an enumerable variant of Solidity's diff --git a/scripts/upgradeable/upgradeable.patch b/scripts/upgradeable/upgradeable.patch index ecd0a3711..466d1d1ca 100644 --- a/scripts/upgradeable/upgradeable.patch +++ b/scripts/upgradeable/upgradeable.patch @@ -59,7 +59,7 @@ index ff596b0c..00000000 - - diff --git a/README.md b/README.md -index 9d1c405b..c264e29c 100644 +index 27627f43..e42a66e8 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ @@ -94,8 +94,8 @@ index 9d1c405b..c264e29c 100644 ```solidity pragma solidity ^0.8.19; --import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -+import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +-import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; ++import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; -contract MyCollectible is ERC721 { - constructor() ERC721("MyCollectible", "MCO") { @@ -106,10 +106,10 @@ index 9d1c405b..c264e29c 100644 } ``` diff --git a/contracts/finance/VestingWallet.sol b/contracts/finance/VestingWallet.sol -index ebdf0a33..8888803e 100644 +index f776a7ca..d7a7e0b0 100644 --- a/contracts/finance/VestingWallet.sol +++ b/contracts/finance/VestingWallet.sol -@@ -18,6 +18,8 @@ import "../utils/Context.sol"; +@@ -19,6 +19,8 @@ import {Context} from "../utils/Context.sol"; * * By setting the duration to 0, one can configure this contract to behave like an asset timelock that hold tokens for * a beneficiary until a specified time. @@ -119,10 +119,10 @@ index ebdf0a33..8888803e 100644 contract VestingWallet is Context { event EtherReleased(uint256 amount); diff --git a/contracts/governance/extensions/GovernorVotes.sol b/contracts/governance/extensions/GovernorVotes.sol -index 5d8318f4..ef3cde55 100644 +index bb14d7fd..0785ebbd 100644 --- a/contracts/governance/extensions/GovernorVotes.sol +++ b/contracts/governance/extensions/GovernorVotes.sol -@@ -10,6 +10,8 @@ import "../../interfaces/IERC5805.sol"; +@@ -12,6 +12,8 @@ import {SafeCast} from "../../utils/math/SafeCast.sol"; * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} token. * * _Available since v4.3._ @@ -152,10 +152,10 @@ index df141192..1cf90ad1 100644 "keywords": [ "solidity", diff --git a/contracts/token/ERC20/extensions/ERC20Capped.sol b/contracts/token/ERC20/extensions/ERC20Capped.sol -index 41e9ce5c..1d910dfa 100644 +index 98ec7144..4992115b 100644 --- a/contracts/token/ERC20/extensions/ERC20Capped.sol +++ b/contracts/token/ERC20/extensions/ERC20Capped.sol -@@ -7,6 +7,8 @@ import "../ERC20.sol"; +@@ -7,6 +7,8 @@ import {ERC20} from "../ERC20.sol"; /** * @dev Extension of {ERC20} that adds a cap to the supply of tokens. @@ -165,10 +165,10 @@ index 41e9ce5c..1d910dfa 100644 abstract contract ERC20Capped is ERC20 { uint256 private immutable _cap; diff --git a/contracts/token/ERC20/extensions/ERC20Permit.sol b/contracts/token/ERC20/extensions/ERC20Permit.sol -index 4378eb7c..1da9e731 100644 +index 8778f4ba..825d4e16 100644 --- a/contracts/token/ERC20/extensions/ERC20Permit.sol +++ b/contracts/token/ERC20/extensions/ERC20Permit.sol -@@ -18,6 +18,8 @@ import "../../../utils/Nonces.sol"; +@@ -18,6 +18,8 @@ import {Nonces} from "../../../utils/Nonces.sol"; * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ @@ -178,10 +178,10 @@ index 4378eb7c..1da9e731 100644 abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces { // solhint-disable-next-line var-name-mixedcase diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol -index 389965e9..66436b14 100644 +index 2cbff622..97f43d7a 100644 --- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol +++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol -@@ -14,6 +14,8 @@ import "../utils/SafeERC20.sol"; +@@ -14,6 +14,8 @@ import {SafeERC20} from "../utils/SafeERC20.sol"; * wrapping of an existing "basic" ERC20 into a governance token. * * _Available since v4.2._ @@ -191,18 +191,18 @@ index 389965e9..66436b14 100644 abstract contract ERC20Wrapper is ERC20 { IERC20 private immutable _underlying; diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol -index 2628014f..7d5193c8 100644 +index d94e956a..86bb5713 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.19; - import "./ECDSA.sol"; --import "../ShortStrings.sol"; - import "../../interfaces/IERC5267.sol"; + import {ECDSA} from "./ECDSA.sol"; +-import {ShortStrings, ShortString} from "../ShortStrings.sol"; + import {IERC5267} from "../../interfaces/IERC5267.sol"; /** -@@ -30,27 +29,19 @@ import "../../interfaces/IERC5267.sol"; +@@ -30,27 +29,19 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; * * _Available since v3.4._ * @@ -361,7 +361,7 @@ index 2628014f..7d5193c8 100644 } } diff --git a/package.json b/package.json -index 37e8f871..d098669f 100644 +index 9eae6732..b3a56366 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ diff --git a/test/governance/Governor.t.sol b/test/governance/Governor.t.sol index 43c4c5ddd..1732fa2f9 100644 --- a/test/governance/Governor.t.sol +++ b/test/governance/Governor.t.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.19; -import "forge-std/Test.sol"; -import "../../contracts/utils/Strings.sol"; -import "../../contracts/governance/Governor.sol"; +import {Test} from "forge-std/Test.sol"; +import {Strings} from "../../contracts/utils/Strings.sol"; +import {Governor} from "../../contracts/governance/Governor.sol"; contract GovernorInternalTest is Test, Governor { constructor() Governor("") {} diff --git a/test/token/ERC721/extensions/ERC721Consecutive.t.sol b/test/token/ERC721/extensions/ERC721Consecutive.t.sol index 896a5ef57..617b17a46 100644 --- a/test/token/ERC721/extensions/ERC721Consecutive.t.sol +++ b/test/token/ERC721/extensions/ERC721Consecutive.t.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.19; // solhint-disable func-name-mixedcase -import "../../../../contracts/token/ERC721/extensions/ERC721Consecutive.sol"; -import "forge-std/Test.sol"; +import {ERC721} from "../../../../contracts/token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "../../../../contracts/token/ERC721/extensions/ERC721Consecutive.sol"; +import {Test, StdUtils} from "forge-std/Test.sol"; function toSingleton(address account) pure returns (address[] memory) { address[] memory accounts = new address[](1); diff --git a/test/utils/ShortStrings.t.sol b/test/utils/ShortStrings.t.sol index b70793bd7..c6aa5355b 100644 --- a/test/utils/ShortStrings.t.sol +++ b/test/utils/ShortStrings.t.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.19; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; -import "../../contracts/utils/ShortStrings.sol"; +import {ShortStrings, ShortString} from "../../contracts/utils/ShortStrings.sol"; contract ShortStringsTest is Test { string _fallback; diff --git a/test/utils/math/Math.t.sol b/test/utils/math/Math.t.sol index 61f558e0e..5a6be476f 100644 --- a/test/utils/math/Math.t.sol +++ b/test/utils/math/Math.t.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.19; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; -import "../../../contracts/utils/math/Math.sol"; +import {Math} from "../../../contracts/utils/math/Math.sol"; contract MathTest is Test { // CEILDIV diff --git a/test/utils/structs/Checkpoints.t.sol b/test/utils/structs/Checkpoints.t.sol index 1fb6dcb4e..bbc309226 100644 --- a/test/utils/structs/Checkpoints.t.sol +++ b/test/utils/structs/Checkpoints.t.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.19; -import "forge-std/Test.sol"; -import "../../../contracts/utils/math/SafeCast.sol"; -import "../../../contracts/utils/structs/Checkpoints.sol"; +import {Test} from "forge-std/Test.sol"; +import {SafeCast} from "../../../contracts/utils/math/SafeCast.sol"; +import {Checkpoints} from "../../../contracts/utils/structs/Checkpoints.sol"; contract CheckpointsTrace224Test is Test { using Checkpoints for Checkpoints.Trace224; From 04342118dcea68981405e4335ff781918a9748c8 Mon Sep 17 00:00:00 2001 From: Hicham010 <47334105+Hicham010@users.noreply.github.com> Date: Fri, 30 Jun 2023 18:08:46 +0200 Subject: [PATCH 04/16] Fix visibility in ERC721._checkOnERC721Received documentation (#4386) --- contracts/token/ERC721/ERC721.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index 4232c616e..ba2b1573f 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -413,7 +413,7 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er } /** - * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID From 621b867b1a14c40c44403f69c71d5317bd49a8da Mon Sep 17 00:00:00 2001 From: Sebastian T F Date: Fri, 30 Jun 2023 22:18:37 +0530 Subject: [PATCH 05/16] Imrove `BitMaps` documentation (#4400) Co-authored-by: Francisco Co-authored-by: ernestognw --- contracts/utils/structs/BitMaps.sol | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/contracts/utils/structs/BitMaps.sol b/contracts/utils/structs/BitMaps.sol index 9786c7f8e..5b62d2f07 100644 --- a/contracts/utils/structs/BitMaps.sol +++ b/contracts/utils/structs/BitMaps.sol @@ -3,8 +3,17 @@ pragma solidity ^0.8.19; /** - * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. + * @dev Library for managing uint256 to bool mapping in a compact and efficient way, provided the keys are sequential. * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. + * + * BitMaps pack 256 booleans across each bit of a single 256-bit slot of `uint256` type. + * Hence booleans corresponding to 256 _sequential_ indices would only consume a single slot, + * unlike the regular `bool` which would consume an entire slot for a single value. + * + * This results in gas savings in two ways: + * + * - Setting a zero value to non-zero only once every 256 times + * - Accessing the same warm slot for every 256 _sequential_ indices */ library BitMaps { struct BitMap { From 37270eb08a15f096e9af38610dabdeacff0b0351 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 30 Jun 2023 16:52:45 -0300 Subject: [PATCH 06/16] Add security considerations to ERC2771Forwarder (#4406) --- contracts/metatx/ERC2771Forwarder.sol | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/contracts/metatx/ERC2771Forwarder.sol b/contracts/metatx/ERC2771Forwarder.sol index 290b438b8..f271d5d3b 100644 --- a/contracts/metatx/ERC2771Forwarder.sol +++ b/contracts/metatx/ERC2771Forwarder.sol @@ -20,6 +20,25 @@ import {Address} from "../utils/Address.sol"; * * `nonce`: A unique transaction ordering identifier to avoid replayability and request invalidation. * * `deadline`: A timestamp after which the request is not executable anymore. * * `data`: Encoded `msg.data` to send with the requested call. + * + * Relayers are able to submit batches if they are processing a high volume of requests. With high + * throughput, relayers may run into limitations of the chain such as limits on the number of + * transactions in the mempool. In these cases the recommendation is to distribute the load among + * multiple accounts. + * + * ==== Security Considerations + * + * If a relayer submits a forward request, it should be willing to pay up to 100% of the gas amount + * specified in the request. This contract does not implement any kind of retribution for this gas, + * and it is assumed that there is an out of band incentive for relayers to pay for execution on + * behalf of signers. Often, the relayer is operated by a project that will consider it a user + * acquisition cost. + * + * By offering to pay for gas, relayers are at risk of having that gas used by an attacker toward + * some other purpose that is not aligned with the expected out of band incentives. If you operate a + * relayer, consider whitelisting target contracts and function selectors. When relaying ERC-721 or + * ERC-1155 transfers specifically, consider rejecting the use of the `data` field, since it can be + * used to execute arbitrary code. */ contract ERC2771Forwarder is EIP712, Nonces { using ECDSA for bytes32; From 06861dce54a0145ede32dcd11e2a6181c250eb0d Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Sat, 1 Jul 2023 07:36:10 +0300 Subject: [PATCH 07/16] Update docs for `SafeERC20.forceApprove` (#4231) --- contracts/token/ERC20/utils/SafeERC20.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/token/ERC20/utils/SafeERC20.sol b/contracts/token/ERC20/utils/SafeERC20.sol index 0ec21573b..51468368f 100644 --- a/contracts/token/ERC20/utils/SafeERC20.sol +++ b/contracts/token/ERC20/utils/SafeERC20.sol @@ -70,8 +70,8 @@ library SafeERC20 { /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, - * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to - * 0 before setting it to a non-zero value. + * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval + * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); From bb64458928d08759e1f36cc0c11a8e76c976de0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Mon, 3 Jul 2023 12:02:06 -0600 Subject: [PATCH 08/16] Implement recommendations from 5.0 audit Phase 1A (#4398) Co-authored-by: Francisco Giordano Co-authored-by: Hadrien Croubois --- contracts/governance/TimelockController.sol | 5 +- contracts/governance/utils/IVotes.sol | 4 +- contracts/interfaces/draft-IERC6093.sol | 1 + contracts/token/ERC1155/ERC1155.sol | 173 ++++++++++------ contracts/token/ERC1155/IERC1155.sol | 14 +- .../ERC1155/extensions/ERC1155Pausable.sol | 7 +- .../ERC1155/extensions/ERC1155Supply.sol | 41 ++-- contracts/token/ERC20/ERC20.sol | 96 ++++----- contracts/token/ERC20/IERC20.sol | 19 +- .../token/ERC20/extensions/ERC20Burnable.sol | 18 +- .../token/ERC20/extensions/ERC20Capped.sol | 4 +- .../token/ERC20/extensions/ERC20FlashMint.sol | 42 ++-- .../token/ERC20/extensions/ERC20Pausable.sol | 6 +- .../token/ERC20/extensions/ERC20Votes.sol | 11 +- .../token/ERC20/extensions/ERC20Wrapper.sol | 18 +- contracts/token/ERC721/ERC721.sol | 4 +- .../ERC721/extensions/ERC721Pausable.sol | 2 +- contracts/utils/Nonces.sol | 2 +- contracts/utils/structs/Checkpoints.sol | 9 +- scripts/generate/templates/Checkpoints.js | 7 +- test/governance/utils/Votes.behavior.js | 16 +- test/token/ERC1155/ERC1155.behavior.js | 195 +++++++++++------- test/token/ERC1155/ERC1155.test.js | 74 +++---- .../extensions/ERC1155Burnable.test.js | 18 +- .../extensions/ERC1155Pausable.test.js | 26 +-- .../ERC1155/extensions/ERC1155Supply.test.js | 40 ++-- .../extensions/ERC1155URIStorage.test.js | 6 +- .../token/ERC1155/utils/ERC1155Holder.test.js | 12 +- test/token/ERC20/ERC20.behavior.js | 122 +++++------ test/token/ERC20/ERC20.test.js | 144 +++++++------ .../extensions/ERC20Burnable.behavior.js | 60 +++--- .../ERC20/extensions/ERC20Capped.behavior.js | 4 +- .../ERC20/extensions/ERC20FlashMint.test.js | 48 ++--- .../ERC20/extensions/ERC20Pausable.test.js | 24 +-- .../token/ERC20/extensions/ERC20Votes.test.js | 38 ++-- .../ERC20/extensions/ERC20Wrapper.test.js | 17 ++ test/token/ERC20/extensions/ERC4626.test.js | 110 +++++----- .../ERC721/extensions/ERC721Votes.test.js | 8 +- 38 files changed, 779 insertions(+), 666 deletions(-) diff --git a/contracts/governance/TimelockController.sol b/contracts/governance/TimelockController.sol index 45d8642e8..56a25fe30 100644 --- a/contracts/governance/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -427,8 +427,9 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { * an operation where the timelock is the target and the data is the ABI-encoded call to this function. */ function updateDelay(uint256 newDelay) external virtual { - if (msg.sender != address(this)) { - revert TimelockUnauthorizedCaller(msg.sender); + address sender = _msgSender(); + if (sender != address(this)) { + revert TimelockUnauthorizedCaller(sender); } emit MinDelayChange(_minDelay, newDelay); _minDelay = newDelay; diff --git a/contracts/governance/utils/IVotes.sol b/contracts/governance/utils/IVotes.sol index a8a20856f..ee17721ff 100644 --- a/contracts/governance/utils/IVotes.sol +++ b/contracts/governance/utils/IVotes.sol @@ -19,9 +19,9 @@ interface IVotes { event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /** - * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes. + * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units. */ - event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance); + event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes); /** * @dev Returns the current amount of votes that `account` has. diff --git a/contracts/interfaces/draft-IERC6093.sol b/contracts/interfaces/draft-IERC6093.sol index fbe31051a..08e77553c 100644 --- a/contracts/interfaces/draft-IERC6093.sol +++ b/contracts/interfaces/draft-IERC6093.sol @@ -118,6 +118,7 @@ interface IERC1155Errors { * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. + * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); diff --git a/contracts/token/ERC1155/ERC1155.sol b/contracts/token/ERC1155/ERC1155.sol index 9d70714fa..a9028f323 100644 --- a/contracts/token/ERC1155/ERC1155.sol +++ b/contracts/token/ERC1155/ERC1155.sol @@ -58,16 +58,12 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER * Clients calling this function must replace the `\{id\}` substring with the * actual token type ID. */ - function uri(uint256) public view virtual returns (string memory) { + function uri(uint256 /* id */) public view virtual returns (string memory) { return _uri; } /** * @dev See {IERC1155-balanceOf}. - * - * Requirements: - * - * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) public view virtual returns (uint256) { return _balances[id][account]; @@ -114,11 +110,12 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER /** * @dev See {IERC1155-safeTransferFrom}. */ - function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) public virtual { - if (from != _msgSender() && !isApprovedForAll(from, _msgSender())) { - revert ERC1155MissingApprovalForAll(_msgSender(), from); + function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual { + address sender = _msgSender(); + if (from != sender && !isApprovedForAll(from, sender)) { + revert ERC1155MissingApprovalForAll(sender, from); } - _safeTransferFrom(from, to, id, amount, data); + _safeTransferFrom(from, to, id, value, data); } /** @@ -128,17 +125,18 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER address from, address to, uint256[] memory ids, - uint256[] memory amounts, + uint256[] memory values, bytes memory data ) public virtual { - if (from != _msgSender() && !isApprovedForAll(from, _msgSender())) { - revert ERC1155MissingApprovalForAll(_msgSender(), from); + address sender = _msgSender(); + if (from != sender && !isApprovedForAll(from, sender)) { + revert ERC1155MissingApprovalForAll(sender, from); } - _safeBatchTransferFrom(from, to, ids, amounts, data); + _safeBatchTransferFrom(from, to, ids, values, data); } /** - * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. Will mint (or burn) if `from` (or `to`) is the zero address. + * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from` (or `to`) is the zero address. * * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise. * @@ -146,75 +144,96 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER * * - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received} * or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value. + * - `ids` and `values` must have the same length. + * + * NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead. */ - function _update( - address from, - address to, - uint256[] memory ids, - uint256[] memory amounts, - bytes memory data - ) internal virtual { - if (ids.length != amounts.length) { - revert ERC1155InvalidArrayLength(ids.length, amounts.length); + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual { + if (ids.length != values.length) { + revert ERC1155InvalidArrayLength(ids.length, values.length); } address operator = _msgSender(); for (uint256 i = 0; i < ids.length; ++i) { uint256 id = ids.unsafeMemoryAccess(i); - uint256 amount = amounts.unsafeMemoryAccess(i); + uint256 value = values.unsafeMemoryAccess(i); if (from != address(0)) { uint256 fromBalance = _balances[id][from]; - if (fromBalance < amount) { - revert ERC1155InsufficientBalance(from, fromBalance, amount, id); + if (fromBalance < value) { + revert ERC1155InsufficientBalance(from, fromBalance, value, id); } unchecked { - _balances[id][from] = fromBalance - amount; + // Overflow not possible: value <= fromBalance + _balances[id][from] = fromBalance - value; } } if (to != address(0)) { - _balances[id][to] += amount; + _balances[id][to] += value; } } if (ids.length == 1) { uint256 id = ids.unsafeMemoryAccess(0); - uint256 amount = amounts.unsafeMemoryAccess(0); - emit TransferSingle(operator, from, to, id, amount); - if (to != address(0)) { - _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); - } + uint256 value = values.unsafeMemoryAccess(0); + emit TransferSingle(operator, from, to, id, value); } else { - emit TransferBatch(operator, from, to, ids, amounts); - if (to != address(0)) { - _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + emit TransferBatch(operator, from, to, ids, values); + } + } + + /** + * @dev Version of {_update} that performs the token acceptance check by calling {IERC1155Receiver-onERC1155Received} + * or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it contains code (eg. is a smart contract + * at the moment of execution). + * + * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any + * update to the contract state after this function would break the check-effect-interaction pattern. Consider + * overriding {_update} instead. + */ + function _updateWithAcceptanceCheck( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) internal virtual { + _update(from, to, ids, values); + if (to != address(0)) { + address operator = _msgSender(); + if (ids.length == 1) { + uint256 id = ids.unsafeMemoryAccess(0); + uint256 value = values.unsafeMemoryAccess(0); + _doSafeTransferAcceptanceCheck(operator, from, to, id, value, data); + } else { + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data); } } } /** - * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * @dev Transfers a `value` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. - * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - `from` must have a balance of tokens of type `id` of at least `value` amount. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ - function _safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) internal { + function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal { if (to == address(0)) { revert ERC1155InvalidReceiver(address(0)); } if (from == address(0)) { revert ERC1155InvalidSender(address(0)); } - (uint256[] memory ids, uint256[] memory amounts) = _asSingletonArrays(id, amount); - _update(from, to, ids, amounts, data); + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(from, to, ids, values, data); } /** @@ -226,12 +245,13 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER * * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. + * - `ids` and `values` must have the same length. */ function _safeBatchTransferFrom( address from, address to, uint256[] memory ids, - uint256[] memory amounts, + uint256[] memory values, bytes memory data ) internal { if (to == address(0)) { @@ -240,7 +260,7 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER if (from == address(0)) { revert ERC1155InvalidSender(address(0)); } - _update(from, to, ids, amounts, data); + _updateWithAcceptanceCheck(from, to, ids, values, data); } /** @@ -249,7 +269,7 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. * * By this mechanism, any occurrence of the `\{id\}` substring in either the - * URI or any of the amounts in the JSON file at said URI will be replaced by + * URI or any of the values in the JSON file at said URI will be replaced by * clients with the token type ID. * * For example, the `https://token-cdn-domain/\{id\}.json` URI would be @@ -267,7 +287,7 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER } /** - * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. + * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`. * * Emits a {TransferSingle} event. * @@ -277,12 +297,12 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ - function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal { + function _mint(address to, uint256 id, uint256 value, bytes memory data) internal { if (to == address(0)) { revert ERC1155InvalidReceiver(address(0)); } - (uint256[] memory ids, uint256[] memory amounts) = _asSingletonArrays(id, amount); - _update(address(0), to, ids, amounts, data); + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(address(0), to, ids, values, data); } /** @@ -292,33 +312,34 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER * * Requirements: * - * - `ids` and `amounts` must have the same length. + * - `ids` and `values` must have the same length. + * - `to` cannot be the zero address. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ - function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal { + function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal { if (to == address(0)) { revert ERC1155InvalidReceiver(address(0)); } - _update(address(0), to, ids, amounts, data); + _updateWithAcceptanceCheck(address(0), to, ids, values, data); } /** - * @dev Destroys `amount` tokens of token type `id` from `from` + * @dev Destroys a `value` amount of tokens of type `id` from `from` * * Emits a {TransferSingle} event. * * Requirements: * * - `from` cannot be the zero address. - * - `from` must have at least `amount` tokens of token type `id`. + * - `from` must have at least `value` amount of tokens of type `id`. */ - function _burn(address from, uint256 id, uint256 amount) internal { + function _burn(address from, uint256 id, uint256 value) internal { if (from == address(0)) { revert ERC1155InvalidSender(address(0)); } - (uint256[] memory ids, uint256[] memory amounts) = _asSingletonArrays(id, amount); - _update(from, address(0), ids, amounts, ""); + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(from, address(0), ids, values, ""); } /** @@ -328,38 +349,48 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER * * Requirements: * - * - `ids` and `amounts` must have the same length. + * - `from` cannot be the zero address. + * - `from` must have at least `value` amount of tokens of type `id`. + * - `ids` and `values` must have the same length. */ - function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal { + function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal { if (from == address(0)) { revert ERC1155InvalidSender(address(0)); } - _update(from, address(0), ids, amounts, ""); + _updateWithAcceptanceCheck(from, address(0), ids, values, ""); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the zero address. */ function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { - if (owner == operator) { - revert ERC1155InvalidOperator(operator); + if (operator == address(0)) { + revert ERC1155InvalidOperator(address(0)); } _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } + /** + * @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address + * if it contains code at the moment of execution. + */ function _doSafeTransferAcceptanceCheck( address operator, address from, address to, uint256 id, - uint256 amount, + uint256 value, bytes memory data ) private { if (to.code.length > 0) { - try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) { if (response != IERC1155Receiver.onERC1155Received.selector) { // Tokens rejected revert ERC1155InvalidReceiver(to); @@ -378,16 +409,20 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER } } + /** + * @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address + * if it contains code at the moment of execution. + */ function _doSafeBatchTransferAcceptanceCheck( address operator, address from, address to, uint256[] memory ids, - uint256[] memory amounts, + uint256[] memory values, bytes memory data ) private { if (to.code.length > 0) { - try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns ( bytes4 response ) { if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { @@ -408,20 +443,28 @@ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IER } } + /** + * @dev Creates an array in memory with only one value for each of the elements provided. + */ function _asSingletonArrays( uint256 element1, uint256 element2 ) private pure returns (uint256[] memory array1, uint256[] memory array2) { /// @solidity memory-safe-assembly assembly { + // Load the free memory pointer array1 := mload(0x40) + // Set array length to 1 mstore(array1, 1) + // Store the single element at the next word after the length (where content starts) mstore(add(array1, 0x20), element1) + // Repeat for next array locating it right after the first array array2 := add(array1, 0x40) mstore(array2, 1) mstore(add(array2, 0x20), element2) + // Update the free memory pointer by pointing after the second array mstore(0x40, add(array2, 0x40)) } } diff --git a/contracts/token/ERC1155/IERC1155.sol b/contracts/token/ERC1155/IERC1155.sol index c450eec2f..1b0b0ae9d 100644 --- a/contracts/token/ERC1155/IERC1155.sol +++ b/contracts/token/ERC1155/IERC1155.sol @@ -13,7 +13,7 @@ import {IERC165} from "../../utils/introspection/IERC165.sol"; */ interface IERC1155 is IERC165 { /** - * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. + * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); @@ -45,7 +45,7 @@ interface IERC1155 is IERC165 { event URI(string value, uint256 indexed id); /** - * @dev Returns the amount of tokens of token type `id` owned by `account`. + * @dev Returns the value of tokens of token type `id` owned by `account`. * * Requirements: * @@ -84,7 +84,7 @@ interface IERC1155 is IERC165 { function isApprovedForAll(address account, address operator) external view returns (bool); /** - * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. * * WARNING: This function can potentially allow a reentrancy attack when transferring tokens * to an untrusted contract, when invoking {onERC1155Received} on the receiver. @@ -97,11 +97,11 @@ interface IERC1155 is IERC165 { * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. - * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - `from` must have a balance of tokens of type `id` of at least `value` amount. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ - function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; + function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. @@ -116,7 +116,7 @@ interface IERC1155 is IERC165 { * * Requirements: * - * - `ids` and `amounts` must have the same length. + * - `ids` and `values` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ @@ -124,7 +124,7 @@ interface IERC1155 is IERC165 { address from, address to, uint256[] calldata ids, - uint256[] calldata amounts, + uint256[] calldata values, bytes calldata data ) external; } diff --git a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol index 05aa8a780..960cd3b6e 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -17,7 +17,7 @@ import {Pausable} from "../../../security/Pausable.sol"; * 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. + * make the contract pause mechanism of the contract unreachable, and thus unusable. * * _Available since v3.1._ */ @@ -33,9 +33,8 @@ abstract contract ERC1155Pausable is ERC1155, Pausable { address from, address to, uint256[] memory ids, - uint256[] memory amounts, - bytes memory data + uint256[] memory values ) internal virtual override whenNotPaused { - super._update(from, to, ids, amounts, data); + super._update(from, to, ids, values); } } diff --git a/contracts/token/ERC1155/extensions/ERC1155Supply.sol b/contracts/token/ERC1155/extensions/ERC1155Supply.sol index eefa0ebf7..ef2736339 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Supply.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Supply.sol @@ -15,20 +15,22 @@ import {ERC1155} from "../ERC1155.sol"; * * NOTE: This contract implies a global limit of 2**256 - 1 to the number of tokens * that can be minted. + * + * CAUTION: This extension should not be added in an upgrade to an already deployed contract. */ abstract contract ERC1155Supply is ERC1155 { mapping(uint256 => uint256) private _totalSupply; uint256 private _totalSupplyAll; /** - * @dev Total amount of tokens in with a given id. + * @dev Total value of tokens in with a given id. */ function totalSupply(uint256 id) public view virtual returns (uint256) { return _totalSupply[id]; } /** - * @dev Total amount of tokens. + * @dev Total value of tokens. */ function totalSupply() public view virtual returns (uint256) { return _totalSupplyAll; @@ -48,35 +50,38 @@ abstract contract ERC1155Supply is ERC1155 { address from, address to, uint256[] memory ids, - uint256[] memory amounts, - bytes memory data + uint256[] memory values ) internal virtual override { + super._update(from, to, ids, values); + if (from == address(0)) { - uint256 totalMintAmount = 0; + uint256 totalMintValue = 0; for (uint256 i = 0; i < ids.length; ++i) { - uint256 amount = amounts[i]; - _totalSupply[ids[i]] += amount; - totalMintAmount += amount; + uint256 value = values[i]; + // Overflow check required: The rest of the code assumes that totalSupply never overflows + _totalSupply[ids[i]] += value; + totalMintValue += value; } - _totalSupplyAll += totalMintAmount; + // Overflow check required: The rest of the code assumes that totalSupplyAll never overflows + _totalSupplyAll += totalMintValue; } if (to == address(0)) { - uint256 totalBurnAmount = 0; + uint256 totalBurnValue = 0; for (uint256 i = 0; i < ids.length; ++i) { - uint256 id = ids[i]; - uint256 amount = amounts[i]; - _totalSupply[id] -= amount; + uint256 value = values[i]; + unchecked { - // Overflow not possible: sum(amounts[i]) <= sum(totalSupply(i)) <= totalSupplyAll - totalBurnAmount += amount; + // Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i]) + _totalSupply[ids[i]] -= value; + // Overflow not possible: sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll + totalBurnValue += value; } } unchecked { - // Overflow not possible: totalBurnAmount = sum(amounts[i]) <= sum(totalSupply(i)) <= totalSupplyAll - _totalSupplyAll -= totalBurnAmount; + // Overflow not possible: totalBurnValue = sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll + _totalSupplyAll -= totalBurnValue; } } - super._update(from, to, ids, amounts, data); } } diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index d43880da6..abaf258c8 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -113,11 +113,11 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { * Requirements: * * - `to` cannot be the zero address. - * - the caller must have a balance of at least `amount`. + * - the caller must have a balance of at least `value`. */ - function transfer(address to, uint256 amount) public virtual returns (bool) { + function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); - _transfer(owner, to, amount); + _transfer(owner, to, value); return true; } @@ -131,16 +131,16 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { /** * @dev See {IERC20-approve}. * - * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on + * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ - function approve(address spender, uint256 amount) public virtual returns (bool) { + function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); - _approve(owner, spender, amount); + _approve(owner, spender, value); return true; } @@ -156,14 +156,14 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { * Requirements: * * - `from` and `to` cannot be the zero address. - * - `from` must have a balance of at least `amount`. + * - `from` must have a balance of at least `value`. * - the caller must have allowance for ``from``'s tokens of at least - * `amount`. + * `value`. */ - function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) { + function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); - _spendAllowance(from, spender, amount); - _transfer(from, to, amount); + _spendAllowance(from, spender, value); + _transfer(from, to, value); return true; } @@ -198,6 +198,9 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `requestedDecrease`. + * + * NOTE: Although this function is designed to avoid double spending with {approval}, + * it can still be frontrunned, preventing any attempt of allowance reduction. */ function decreaseAllowance(address spender, uint256 requestedDecrease) public virtual returns (bool) { address owner = _msgSender(); @@ -213,7 +216,7 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { } /** - * @dev Moves `amount` of tokens from `from` to `to`. + * @dev Moves a `value` amount of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. @@ -222,83 +225,84 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { * * NOTE: This function is not virtual, {_update} should be overridden instead. */ - function _transfer(address from, address to, uint256 amount) internal { + function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } - _update(from, to, amount); + _update(from, to, value); } /** - * @dev Transfers `amount` of tokens from `from` to `to`, or alternatively mints (or burns) if `from` (or `to`) is + * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` (or `to`) is * the zero address. All customizations to transfers, mints, and burns should be done by overriding this function. * * Emits a {Transfer} event. */ - function _update(address from, address to, uint256 amount) internal virtual { + function _update(address from, address to, uint256 value) internal virtual { if (from == address(0)) { - _totalSupply += amount; + // Overflow check required: The rest of the code assumes that totalSupply never overflows + _totalSupply += value; } else { uint256 fromBalance = _balances[from]; - if (fromBalance < amount) { - revert ERC20InsufficientBalance(from, fromBalance, amount); + if (fromBalance < value) { + revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { - // Overflow not possible: amount <= fromBalance <= totalSupply. - _balances[from] = fromBalance - amount; + // Overflow not possible: value <= fromBalance <= totalSupply. + _balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { - // Overflow not possible: amount <= totalSupply or amount <= fromBalance <= totalSupply. - _totalSupply -= amount; + // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. + _totalSupply -= value; } } else { unchecked { - // Overflow not possible: balance + amount is at most totalSupply, which we know fits into a uint256. - _balances[to] += amount; + // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. + _balances[to] += value; } } - emit Transfer(from, to, amount); + emit Transfer(from, to, value); } /** - * @dev Creates `amount` tokens and assigns them to `account`, by transferring it from address(0). + * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ - function _mint(address account, uint256 amount) internal { + function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } - _update(address(0), account, amount); + _update(address(0), account, value); } /** - * @dev Destroys `amount` tokens from `account`, by transferring it to address(0). + * @dev Destroys a `value` amount of tokens from `account`, by transferring it to address(0). * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ - function _burn(address account, uint256 amount) internal { + function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } - _update(account, address(0), amount); + _update(account, address(0), value); } /** - * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. @@ -310,8 +314,8 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ - function _approve(address owner, address spender, uint256 amount) internal virtual { - _approve(owner, spender, amount, true); + function _approve(address owner, address spender, uint256 value) internal virtual { + _approve(owner, spender, value, true); } /** @@ -324,42 +328,42 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to true * using the following override: * ``` - * function _approve(address owner, address spender, uint256 amount, bool) internal virtual override { - * super._approve(owner, spender, amount, true); + * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { + * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ - function _approve(address owner, address spender, uint256 amount, bool emitEvent) internal virtual { + function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } - _allowances[owner][spender] = amount; + _allowances[owner][spender] = value; if (emitEvent) { - emit Approval(owner, spender, amount); + emit Approval(owner, spender, value); } } /** - * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * @dev Updates `owner` s allowance for `spender` based on spent `value`. * - * Does not update the allowance amount in case of infinite allowance. + * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ - function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { + function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { - if (currentAllowance < amount) { - revert ERC20InsufficientAllowance(spender, currentAllowance, amount); + if (currentAllowance < value) { + revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { - _approve(owner, spender, currentAllowance - amount, false); + _approve(owner, spender, currentAllowance - value, false); } } } diff --git a/contracts/token/ERC20/IERC20.sol b/contracts/token/ERC20/IERC20.sol index a19535a30..eed63a606 100644 --- a/contracts/token/ERC20/IERC20.sol +++ b/contracts/token/ERC20/IERC20.sol @@ -22,23 +22,23 @@ interface IERC20 { event Approval(address indexed owner, address indexed spender, uint256 value); /** - * @dev Returns the amount of tokens in existence. + * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** - * @dev Returns the amount of tokens owned by `account`. + * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** - * @dev Moves `amount` tokens from the caller's account to `to`. + * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ - function transfer(address to, uint256 amount) external returns (bool); + function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be @@ -50,7 +50,8 @@ interface IERC20 { function allowance(address owner, address spender) external view returns (uint256); /** - * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * @@ -63,16 +64,16 @@ interface IERC20 { * * Emits an {Approval} event. */ - function approve(address spender, uint256 amount) external returns (bool); + function approve(address spender, uint256 value) external returns (bool); /** - * @dev Moves `amount` tokens from `from` to `to` using the - * allowance mechanism. `amount` is then deducted from the caller's + * @dev Moves a `value` amount of tokens from `from` to `to` using the + * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ - function transferFrom(address from, address to, uint256 amount) external returns (bool); + function transferFrom(address from, address to, uint256 value) external returns (bool); } diff --git a/contracts/token/ERC20/extensions/ERC20Burnable.sol b/contracts/token/ERC20/extensions/ERC20Burnable.sol index 2a6d28963..e5b43a780 100644 --- a/contracts/token/ERC20/extensions/ERC20Burnable.sol +++ b/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -13,27 +13,27 @@ import {Context} from "../../../utils/Context.sol"; */ abstract contract ERC20Burnable is Context, ERC20 { /** - * @dev Destroys `amount` tokens from the caller. + * @dev Destroys a `value` amount of tokens from the caller. * * See {ERC20-_burn}. */ - function burn(uint256 amount) public virtual { - _burn(_msgSender(), amount); + function burn(uint256 value) public virtual { + _burn(_msgSender(), value); } /** - * @dev Destroys `amount` tokens from `account`, deducting from the caller's - * allowance. + * @dev Destroys a `value` amount of tokens from `account`, deducting from + * the caller's allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least - * `amount`. + * `value`. */ - function burnFrom(address account, uint256 amount) public virtual { - _spendAllowance(account, _msgSender(), amount); - _burn(account, amount); + function burnFrom(address account, uint256 value) public virtual { + _spendAllowance(account, _msgSender(), value); + _burn(account, value); } } diff --git a/contracts/token/ERC20/extensions/ERC20Capped.sol b/contracts/token/ERC20/extensions/ERC20Capped.sol index 98ec71443..943d01644 100644 --- a/contracts/token/ERC20/extensions/ERC20Capped.sol +++ b/contracts/token/ERC20/extensions/ERC20Capped.sol @@ -42,8 +42,8 @@ abstract contract ERC20Capped is ERC20 { /** * @dev See {ERC20-_update}. */ - function _update(address from, address to, uint256 amount) internal virtual override { - super._update(from, to, amount); + function _update(address from, address to, uint256 value) internal virtual override { + super._update(from, to, value); if (from == address(0)) { uint256 maxSupply = cap(); diff --git a/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/contracts/token/ERC20/extensions/ERC20FlashMint.sol index b63c75f71..0583af5df 100644 --- a/contracts/token/ERC20/extensions/ERC20FlashMint.sol +++ b/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -14,6 +14,10 @@ import {ERC20} from "../ERC20.sol"; * Adds the {flashLoan} method, which provides flash loan support at the token * level. By default there is no fee, but this can be changed by overriding {flashFee}. * + * NOTE: When this extension is used along with the {ERC20Capped} or {ERC20Votes} extensions, + * {maxFlashLoan} will not correctly reflect the maximum that can be flash minted. We recommend + * overriding {maxFlashLoan} so that it correctly reflects the supply cap. + * * _Available since v4.1._ */ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { @@ -25,7 +29,7 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { error ERC3156UnsupportedToken(address token); /** - * @dev The requested loan exceeds the max loan amount for `token`. + * @dev The requested loan exceeds the max loan value for `token`. */ error ERC3156ExceededMaxLoan(uint256 maxLoan); @@ -38,6 +42,10 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { * @dev Returns the maximum amount of tokens available for loan. * @param token The address of the token that is requested. * @return The amount of token that can be loaned. + * + * NOTE: This function does not consider any form of supply cap, so in case + * it's used in a token with a cap like {ERC20Capped}, make sure to override this + * function to integrate the cap instead of `type(uint256).max`. */ function maxFlashLoan(address token) public view virtual returns (uint256) { return token == address(this) ? type(uint256).max - totalSupply() : 0; @@ -48,14 +56,14 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { * the {_flashFee} function which returns the fee applied when doing flash * loans. * @param token The token to be flash loaned. - * @param amount The amount of tokens to be loaned. + * @param value The amount of tokens to be loaned. * @return The fees applied to the corresponding flash loan. */ - function flashFee(address token, uint256 amount) public view virtual returns (uint256) { + function flashFee(address token, uint256 value) public view virtual returns (uint256) { if (token != address(this)) { revert ERC3156UnsupportedToken(token); } - return _flashFee(token, amount); + return _flashFee(token, value); } /** @@ -63,13 +71,13 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { * implementation has 0 fees. This function can be overloaded to make * the flash loan mechanism deflationary. * @param token The token to be flash loaned. - * @param amount The amount of tokens to be loaned. + * @param value The amount of tokens to be loaned. * @return The fees applied to the corresponding flash loan. */ - function _flashFee(address token, uint256 amount) internal view virtual returns (uint256) { + function _flashFee(address token, uint256 value) internal view virtual returns (uint256) { // silence warning about unused variable without the addition of bytecode. token; - amount; + value; return 0; } @@ -87,13 +95,13 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { * @dev Performs a flash loan. New tokens are minted and sent to the * `receiver`, who is required to implement the {IERC3156FlashBorrower} * interface. By the end of the flash loan, the receiver is expected to own - * amount + fee tokens and have them approved back to the token contract itself so + * value + fee tokens and have them approved back to the token contract itself so * they can be burned. * @param receiver The receiver of the flash loan. Should implement the * {IERC3156FlashBorrower-onFlashLoan} interface. * @param token The token to be flash loaned. Only `address(this)` is * supported. - * @param amount The amount of tokens to be loaned. + * @param value The amount of tokens to be loaned. * @param data An arbitrary datafield that is passed to the receiver. * @return `true` if the flash loan was successful. */ @@ -103,24 +111,24 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { function flashLoan( IERC3156FlashBorrower receiver, address token, - uint256 amount, + uint256 value, bytes calldata data ) public virtual returns (bool) { uint256 maxLoan = maxFlashLoan(token); - if (amount > maxLoan) { + if (value > maxLoan) { revert ERC3156ExceededMaxLoan(maxLoan); } - uint256 fee = flashFee(token, amount); - _mint(address(receiver), amount); - if (receiver.onFlashLoan(msg.sender, token, amount, fee, data) != _RETURN_VALUE) { + uint256 fee = flashFee(token, value); + _mint(address(receiver), value); + if (receiver.onFlashLoan(_msgSender(), token, value, fee, data) != _RETURN_VALUE) { revert ERC3156InvalidReceiver(address(receiver)); } address flashFeeReceiver = _flashFeeReceiver(); - _spendAllowance(address(receiver), address(this), amount + fee); + _spendAllowance(address(receiver), address(this), value + fee); if (fee == 0 || flashFeeReceiver == address(0)) { - _burn(address(receiver), amount + fee); + _burn(address(receiver), value + fee); } else { - _burn(address(receiver), amount); + _burn(address(receiver), value); _transfer(address(receiver), flashFeeReceiver, fee); } return true; diff --git a/contracts/token/ERC20/extensions/ERC20Pausable.sol b/contracts/token/ERC20/extensions/ERC20Pausable.sol index 59f451639..6fff5058f 100644 --- a/contracts/token/ERC20/extensions/ERC20Pausable.sol +++ b/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -17,7 +17,7 @@ import {Pausable} from "../../../security/Pausable.sol"; * 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. + * make the contract pause mechanism of the contract unreachable, and thus unusable. */ abstract contract ERC20Pausable is ERC20, Pausable { /** @@ -27,7 +27,7 @@ abstract contract ERC20Pausable is ERC20, Pausable { * * - the contract must not be paused. */ - function _update(address from, address to, uint256 amount) internal virtual override whenNotPaused { - super._update(from, to, amount); + function _update(address from, address to, uint256 value) internal virtual override whenNotPaused { + super._update(from, to, value); } } diff --git a/contracts/token/ERC20/extensions/ERC20Votes.sol b/contracts/token/ERC20/extensions/ERC20Votes.sol index db5f71241..c27115eaa 100644 --- a/contracts/token/ERC20/extensions/ERC20Votes.sol +++ b/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -41,8 +41,8 @@ abstract contract ERC20Votes is ERC20, Votes { * * Emits a {IVotes-DelegateVotesChanged} event. */ - function _update(address from, address to, uint256 amount) internal virtual override { - super._update(from, to, amount); + function _update(address from, address to, uint256 value) internal virtual override { + super._update(from, to, value); if (from == address(0)) { uint256 supply = totalSupply(); uint256 cap = _maxSupply(); @@ -50,11 +50,14 @@ abstract contract ERC20Votes is ERC20, Votes { revert ERC20ExceededSafeSupply(supply, cap); } } - _transferVotingUnits(from, to, amount); + _transferVotingUnits(from, to, value); } /** - * @dev Returns the balance of `account`. + * @dev Returns the voting units of an `account`. + * + * WARNING: Overriding this function may compromise the internal vote accounting. + * `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change. */ function _getVotingUnits(address account) internal view virtual override returns (uint256) { return balanceOf(account); diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol index 2cbff6223..c9e33d00a 100644 --- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol +++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -51,22 +51,28 @@ abstract contract ERC20Wrapper is ERC20 { /** * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens. */ - function depositFor(address account, uint256 amount) public virtual returns (bool) { + function depositFor(address account, uint256 value) public virtual returns (bool) { address sender = _msgSender(); if (sender == address(this)) { revert ERC20InvalidSender(address(this)); } - SafeERC20.safeTransferFrom(_underlying, sender, address(this), amount); - _mint(account, amount); + if (account == address(this)) { + revert ERC20InvalidReceiver(account); + } + SafeERC20.safeTransferFrom(_underlying, sender, address(this), value); + _mint(account, value); return true; } /** * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens. */ - function withdrawTo(address account, uint256 amount) public virtual returns (bool) { - _burn(_msgSender(), amount); - SafeERC20.safeTransfer(_underlying, account, amount); + function withdrawTo(address account, uint256 value) public virtual returns (bool) { + if (account == address(this)) { + revert ERC20InvalidReceiver(account); + } + _burn(_msgSender(), value); + SafeERC20.safeTransfer(_underlying, account, value); return true; } diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index ba2b1573f..25ac69fa9 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -486,7 +486,7 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er * that `ownerOf(tokenId)` is `a`. */ // solhint-disable-next-line func-name-mixedcase - function __unsafe_increaseBalance(address account, uint256 amount) internal { - _balances[account] += amount; + function __unsafe_increaseBalance(address account, uint256 value) internal { + _balances[account] += value; } } diff --git a/contracts/token/ERC721/extensions/ERC721Pausable.sol b/contracts/token/ERC721/extensions/ERC721Pausable.sol index a4effc549..5777ac36e 100644 --- a/contracts/token/ERC721/extensions/ERC721Pausable.sol +++ b/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -17,7 +17,7 @@ import {Pausable} from "../../../security/Pausable.sol"; * 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. + * make the contract pause mechanism of the contract unreachable, and thus unusable. */ abstract contract ERC721Pausable is ERC721, Pausable { /** diff --git a/contracts/utils/Nonces.sol b/contracts/utils/Nonces.sol index f8ea1dfd3..d5458b10a 100644 --- a/contracts/utils/Nonces.sol +++ b/contracts/utils/Nonces.sol @@ -13,7 +13,7 @@ abstract contract Nonces { mapping(address => uint256) private _nonces; /** - * @dev Returns an address nonce. + * @dev Returns an the next unused nonce for an address. */ function nonces(address owner) public view virtual returns (uint256) { return _nonces[owner]; diff --git a/contracts/utils/structs/Checkpoints.sol b/contracts/utils/structs/Checkpoints.sol index 47ad91bbf..56b7035b9 100644 --- a/contracts/utils/structs/Checkpoints.sol +++ b/contracts/utils/structs/Checkpoints.sol @@ -5,13 +5,12 @@ pragma solidity ^0.8.19; import {Math} from "../math/Math.sol"; -import {SafeCast} from "../math/SafeCast.sol"; /** - * @dev This library defines the `History` struct, for checkpointing values as they change at different points in + * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in * time, and later looking up past values by block number. See {Votes} as an example. * - * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new + * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new * checkpoint for the current transaction block using the {push} function. * * _Available since v4.5._ @@ -35,6 +34,8 @@ library Checkpoints { * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. * * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the library. */ function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) { return _insert(self._checkpoints, key, value); @@ -220,6 +221,8 @@ library Checkpoints { * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. * * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the library. */ function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) { return _insert(self._checkpoints, key, value); diff --git a/scripts/generate/templates/Checkpoints.js b/scripts/generate/templates/Checkpoints.js index d5ab745a0..d635c8462 100644 --- a/scripts/generate/templates/Checkpoints.js +++ b/scripts/generate/templates/Checkpoints.js @@ -6,13 +6,12 @@ const header = `\ pragma solidity ^0.8.19; import {Math} from "../math/Math.sol"; -import {SafeCast} from "../math/SafeCast.sol"; /** - * @dev This library defines the \`History\` struct, for checkpointing values as they change at different points in + * @dev This library defines the \`Trace*\` struct, for checkpointing values as they change at different points in * time, and later looking up past values by block number. See {Votes} as an example. * - * To create a history of checkpoints define a variable type \`Checkpoints.History\` in your contract, and store a new + * To create a history of checkpoints define a variable type \`Checkpoints.Trace*\` in your contract, and store a new * checkpoint for the current transaction block using the {push} function. * * _Available since v4.5._ @@ -40,6 +39,8 @@ struct ${opts.checkpointTypeName} { * @dev Pushes a (\`key\`, \`value\`) pair into a ${opts.historyTypeName} so that it is stored as the checkpoint. * * Returns previous value and new value. + * + * IMPORTANT: Never accept \`key\` as a user input, since an arbitrary \`type(${opts.keyTypeName}).max\` key set will disable the library. */ function push( ${opts.historyTypeName} storage self, diff --git a/test/governance/utils/Votes.behavior.js b/test/governance/utils/Votes.behavior.js index 20ebdba4f..5836cc351 100644 --- a/test/governance/utils/Votes.behavior.js +++ b/test/governance/utils/Votes.behavior.js @@ -70,8 +70,8 @@ function shouldBehaveLikeVotes(accounts, tokens, { mode = 'blocknumber', fungibl }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: accounts[1], - previousBalance: '0', - newBalance: weight, + previousVotes: '0', + newVotes: weight, }); expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[1]); @@ -100,13 +100,13 @@ function shouldBehaveLikeVotes(accounts, tokens, { mode = 'blocknumber', fungibl }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: accounts[1], - previousBalance: weight, - newBalance: '0', + previousVotes: weight, + newVotes: '0', }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: accounts[2], - previousBalance: '0', - newBalance: weight, + previousVotes: '0', + newVotes: weight, }); expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[2]); @@ -152,8 +152,8 @@ function shouldBehaveLikeVotes(accounts, tokens, { mode = 'blocknumber', fungibl }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: delegatee, - previousBalance: '0', - newBalance: weight, + previousVotes: '0', + newVotes: weight, }); expect(await this.votes.delegates(delegator.address)).to.be.equal(delegatee); diff --git a/test/token/ERC1155/ERC1155.behavior.js b/test/token/ERC1155/ERC1155.behavior.js index 4bf4a7319..8df30a814 100644 --- a/test/token/ERC1155/ERC1155.behavior.js +++ b/test/token/ERC1155/ERC1155.behavior.js @@ -14,8 +14,8 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m const secondTokenId = new BN(2); const unknownTokenId = new BN(3); - const firstAmount = new BN(1000); - const secondAmount = new BN(2000); + const firstTokenValue = new BN(1000); + const secondTokenValue = new BN(2000); const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; @@ -38,18 +38,18 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m context('when accounts own some tokens', function () { beforeEach(async function () { - await this.token.$_mint(firstTokenHolder, firstTokenId, firstAmount, '0x', { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstTokenValue, '0x', { from: minter, }); - await this.token.$_mint(secondTokenHolder, secondTokenId, secondAmount, '0x', { + await this.token.$_mint(secondTokenHolder, secondTokenId, secondTokenValue, '0x', { from: minter, }); }); it('returns the amount of tokens owned by the given addresses', async function () { - expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal(firstAmount); + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal(firstTokenValue); - expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal(secondAmount); + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal(secondTokenValue); expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); }); @@ -99,10 +99,10 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m context('when accounts own some tokens', function () { beforeEach(async function () { - await this.token.$_mint(firstTokenHolder, firstTokenId, firstAmount, '0x', { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstTokenValue, '0x', { from: minter, }); - await this.token.$_mint(secondTokenHolder, secondTokenId, secondAmount, '0x', { + await this.token.$_mint(secondTokenHolder, secondTokenId, secondTokenValue, '0x', { from: minter, }); }); @@ -113,8 +113,8 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m [secondTokenId, firstTokenId, unknownTokenId], ); expect(result).to.be.an('array'); - expect(result[0]).to.be.a.bignumber.equal(secondAmount); - expect(result[1]).to.be.a.bignumber.equal(firstAmount); + expect(result[0]).to.be.a.bignumber.equal(secondTokenValue); + expect(result[1]).to.be.a.bignumber.equal(firstTokenValue); expect(result[2]).to.be.a.bignumber.equal('0'); }); @@ -125,9 +125,9 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m ); expect(result).to.be.an('array'); expect(result[0]).to.be.a.bignumber.equal(result[2]); - expect(result[0]).to.be.a.bignumber.equal(firstAmount); - expect(result[1]).to.be.a.bignumber.equal(secondAmount); - expect(result[2]).to.be.a.bignumber.equal(firstAmount); + expect(result[0]).to.be.a.bignumber.equal(firstTokenValue); + expect(result[1]).to.be.a.bignumber.equal(secondTokenValue); + expect(result[2]).to.be.a.bignumber.equal(firstTokenValue); }); }); }); @@ -151,38 +151,38 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(false); }); - it('reverts if attempting to approve self as an operator', async function () { + it('reverts if attempting to approve zero address as an operator', async function () { await expectRevertCustomError( - this.token.setApprovalForAll(multiTokenHolder, true, { from: multiTokenHolder }), + this.token.setApprovalForAll(constants.ZERO_ADDRESS, true, { from: multiTokenHolder }), 'ERC1155InvalidOperator', - [multiTokenHolder], + [constants.ZERO_ADDRESS], ); }); }); describe('safeTransferFrom', function () { beforeEach(async function () { - await this.token.$_mint(multiTokenHolder, firstTokenId, firstAmount, '0x', { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstTokenValue, '0x', { from: minter, }); - await this.token.$_mint(multiTokenHolder, secondTokenId, secondAmount, '0x', { + await this.token.$_mint(multiTokenHolder, secondTokenId, secondTokenValue, '0x', { from: minter, }); }); it('reverts when transferring more than balance', async function () { await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount.addn(1), '0x', { + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstTokenValue.addn(1), '0x', { from: multiTokenHolder, }), 'ERC1155InsufficientBalance', - [multiTokenHolder, firstAmount, firstAmount.addn(1), firstTokenId], + [multiTokenHolder, firstTokenValue, firstTokenValue.addn(1), firstTokenId], ); }); it('reverts when transferring to zero address', async function () { await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, ZERO_ADDRESS, firstTokenId, firstAmount, '0x', { + this.token.safeTransferFrom(multiTokenHolder, ZERO_ADDRESS, firstTokenId, firstTokenValue, '0x', { from: multiTokenHolder, }), 'ERC1155InvalidReceiver', @@ -219,7 +219,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, recipient, firstTokenId, - firstAmount, + firstTokenValue, '0x', { from: multiTokenHolder, @@ -231,12 +231,12 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, id: firstTokenId, - value: firstAmount, + value: firstTokenValue, }); it('preserves existing balances which are not transferred by multiTokenHolder', async function () { const balance1 = await this.token.balanceOf(multiTokenHolder, secondTokenId); - expect(balance1).to.be.a.bignumber.equal(secondAmount); + expect(balance1).to.be.a.bignumber.equal(secondTokenValue); const balance2 = await this.token.balanceOf(recipient, secondTokenId); expect(balance2).to.be.a.bignumber.equal('0'); @@ -251,7 +251,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m it('reverts', async function () { await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount, '0x', { + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstTokenValue, '0x', { from: proxy, }), 'ERC1155MissingApprovalForAll', @@ -268,7 +268,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, recipient, firstTokenId, - firstAmount, + firstTokenValue, '0x', { from: proxy, @@ -280,7 +280,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: proxy, from: multiTokenHolder, id: firstTokenId, - value: firstAmount, + value: firstTokenValue, }); it("preserves operator's balances not involved in the transfer", async function () { @@ -309,7 +309,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, firstTokenId, - firstAmount, + firstTokenValue, '0x', { from: multiTokenHolder }, ); @@ -320,7 +320,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, id: firstTokenId, - value: firstAmount, + value: firstTokenValue, }); it('calls onERC1155Received', async function () { @@ -328,7 +328,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, id: firstTokenId, - value: firstAmount, + value: firstTokenValue, data: null, }); }); @@ -342,7 +342,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, firstTokenId, - firstAmount, + firstTokenValue, data, { from: multiTokenHolder }, ); @@ -353,7 +353,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, id: firstTokenId, - value: firstAmount, + value: firstTokenValue, }); it('calls onERC1155Received', async function () { @@ -361,7 +361,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, id: firstTokenId, - value: firstAmount, + value: firstTokenValue, data, }); }); @@ -375,7 +375,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m it('reverts', async function () { await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { + this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstTokenValue, '0x', { from: multiTokenHolder, }), 'ERC1155InvalidReceiver', @@ -396,9 +396,16 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m it('reverts', async function () { await expectRevert( - this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { - from: multiTokenHolder, - }), + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), 'ERC1155ReceiverMock: reverting on receive', ); }); @@ -415,9 +422,16 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m it('reverts', async function () { await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { - from: multiTokenHolder, - }), + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), 'ERC1155InvalidReceiver', [this.receiver.address], ); @@ -435,9 +449,16 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m it('reverts', async function () { await expectRevertCustomError( - this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { - from: multiTokenHolder, - }), + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), 'CustomError', [RECEIVER_SINGLE_MAGIC_VALUE], ); @@ -455,9 +476,16 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m it('reverts', async function () { await expectRevert.unspecified( - this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { - from: multiTokenHolder, - }), + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), ); }); }); @@ -467,9 +495,16 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m it('reverts', async function () { const invalidReceiver = this.token; await expectRevert.unspecified( - this.token.safeTransferFrom(multiTokenHolder, invalidReceiver.address, firstTokenId, firstAmount, '0x', { - from: multiTokenHolder, - }), + this.token.safeTransferFrom( + multiTokenHolder, + invalidReceiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), ); }); }); @@ -477,49 +512,49 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m describe('safeBatchTransferFrom', function () { beforeEach(async function () { - await this.token.$_mint(multiTokenHolder, firstTokenId, firstAmount, '0x', { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstTokenValue, '0x', { from: minter, }); - await this.token.$_mint(multiTokenHolder, secondTokenId, secondAmount, '0x', { + await this.token.$_mint(multiTokenHolder, secondTokenId, secondTokenValue, '0x', { from: minter, }); }); - it('reverts when transferring amount more than any of balances', async function () { + it('reverts when transferring value more than any of balances', async function () { await expectRevertCustomError( this.token.safeBatchTransferFrom( multiTokenHolder, recipient, [firstTokenId, secondTokenId], - [firstAmount, secondAmount.addn(1)], + [firstTokenValue, secondTokenValue.addn(1)], '0x', { from: multiTokenHolder }, ), 'ERC1155InsufficientBalance', - [multiTokenHolder, secondAmount, secondAmount.addn(1), secondTokenId], + [multiTokenHolder, secondTokenValue, secondTokenValue.addn(1), secondTokenId], ); }); - it("reverts when ids array length doesn't match amounts array length", async function () { + it("reverts when ids array length doesn't match values array length", async function () { const ids1 = [firstTokenId]; - const amounts1 = [firstAmount, secondAmount]; + const tokenValues1 = [firstTokenValue, secondTokenValue]; await expectRevertCustomError( - this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids1, amounts1, '0x', { + this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids1, tokenValues1, '0x', { from: multiTokenHolder, }), 'ERC1155InvalidArrayLength', - [ids1.length, amounts1.length], + [ids1.length, tokenValues1.length], ); const ids2 = [firstTokenId, secondTokenId]; - const amounts2 = [firstAmount]; + const tokenValues2 = [firstTokenValue]; await expectRevertCustomError( - this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids2, amounts2, '0x', { + this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids2, tokenValues2, '0x', { from: multiTokenHolder, }), 'ERC1155InvalidArrayLength', - [ids2.length, amounts2.length], + [ids2.length, tokenValues2.length], ); }); @@ -529,7 +564,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, ZERO_ADDRESS, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ), @@ -540,7 +575,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m it('reverts when transferring from zero address', async function () { await expectRevertCustomError( - this.token.$_safeBatchTransferFrom(ZERO_ADDRESS, multiTokenHolder, [firstTokenId], [firstAmount], '0x'), + this.token.$_safeBatchTransferFrom(ZERO_ADDRESS, multiTokenHolder, [firstTokenId], [firstTokenValue], '0x'), 'ERC1155InvalidSender', [ZERO_ADDRESS], ); @@ -579,7 +614,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, recipient, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ); @@ -589,7 +624,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, ids: [firstTokenId, secondTokenId], - values: [firstAmount, secondAmount], + values: [firstTokenValue, secondTokenValue], }); }); @@ -605,7 +640,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, recipient, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: proxy }, ), @@ -623,7 +658,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, recipient, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: proxy }, ); @@ -633,7 +668,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: proxy, from: multiTokenHolder, ids: [firstTokenId, secondTokenId], - values: [firstAmount, secondAmount], + values: [firstTokenValue, secondTokenValue], }); it("preserves operator's balances not involved in the transfer", async function () { @@ -661,7 +696,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ); @@ -672,7 +707,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, ids: [firstTokenId, secondTokenId], - values: [firstAmount, secondAmount], + values: [firstTokenValue, secondTokenValue], }); it('calls onERC1155BatchReceived', async function () { @@ -680,7 +715,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, // ids: [firstTokenId, secondTokenId], - // values: [firstAmount, secondAmount], + // values: [firstTokenValue, secondTokenValue], data: null, }); }); @@ -694,7 +729,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], data, { from: multiTokenHolder }, ); @@ -705,7 +740,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, ids: [firstTokenId, secondTokenId], - values: [firstAmount, secondAmount], + values: [firstTokenValue, secondTokenValue], }); it('calls onERC1155Received', async function () { @@ -713,7 +748,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m operator: multiTokenHolder, from: multiTokenHolder, // ids: [firstTokenId, secondTokenId], - // values: [firstAmount, secondAmount], + // values: [firstTokenValue, secondTokenValue], data, }); }); @@ -735,7 +770,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ), @@ -761,7 +796,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ), @@ -785,7 +820,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ), @@ -810,7 +845,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ), @@ -835,7 +870,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, this.receiver.address, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ), @@ -852,7 +887,7 @@ function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, m multiTokenHolder, invalidReceiver.address, [firstTokenId, secondTokenId], - [firstAmount, secondAmount], + [firstTokenValue, secondTokenValue], '0x', { from: multiTokenHolder }, ), diff --git a/test/token/ERC1155/ERC1155.test.js b/test/token/ERC1155/ERC1155.test.js index 23555dd54..58d747a4b 100644 --- a/test/token/ERC1155/ERC1155.test.js +++ b/test/token/ERC1155/ERC1155.test.js @@ -21,19 +21,19 @@ contract('ERC1155', function (accounts) { describe('internal functions', function () { const tokenId = new BN(1990); - const mintAmount = new BN(9001); - const burnAmount = new BN(3000); + const mintValue = new BN(9001); + const burnValue = new BN(3000); const tokenBatchIds = [new BN(2000), new BN(2010), new BN(2020)]; - const mintAmounts = [new BN(5000), new BN(10000), new BN(42195)]; - const burnAmounts = [new BN(5000), new BN(9001), new BN(195)]; + const mintValues = [new BN(5000), new BN(10000), new BN(42195)]; + const burnValues = [new BN(5000), new BN(9001), new BN(195)]; const data = '0x12345678'; describe('_mint', function () { it('reverts with a zero destination address', async function () { await expectRevertCustomError( - this.token.$_mint(ZERO_ADDRESS, tokenId, mintAmount, data), + this.token.$_mint(ZERO_ADDRESS, tokenId, mintValue, data), 'ERC1155InvalidReceiver', [ZERO_ADDRESS], ); @@ -41,7 +41,7 @@ contract('ERC1155', function (accounts) { context('with minted tokens', function () { beforeEach(async function () { - this.receipt = await this.token.$_mint(tokenHolder, tokenId, mintAmount, data, { from: operator }); + this.receipt = await this.token.$_mint(tokenHolder, tokenId, mintValue, data, { from: operator }); }); it('emits a TransferSingle event', function () { @@ -50,12 +50,12 @@ contract('ERC1155', function (accounts) { from: ZERO_ADDRESS, to: tokenHolder, id: tokenId, - value: mintAmount, + value: mintValue, }); }); - it('credits the minted amount of tokens', async function () { - expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintAmount); + it('credits the minted token value', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintValue); }); }); }); @@ -63,7 +63,7 @@ contract('ERC1155', function (accounts) { describe('_mintBatch', function () { it('reverts with a zero destination address', async function () { await expectRevertCustomError( - this.token.$_mintBatch(ZERO_ADDRESS, tokenBatchIds, mintAmounts, data), + this.token.$_mintBatch(ZERO_ADDRESS, tokenBatchIds, mintValues, data), 'ERC1155InvalidReceiver', [ZERO_ADDRESS], ); @@ -71,21 +71,21 @@ contract('ERC1155', function (accounts) { it('reverts if length of inputs do not match', async function () { await expectRevertCustomError( - this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts.slice(1), data), + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues.slice(1), data), 'ERC1155InvalidArrayLength', - [tokenBatchIds.length, mintAmounts.length - 1], + [tokenBatchIds.length, mintValues.length - 1], ); await expectRevertCustomError( - this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds.slice(1), mintAmounts, data), + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds.slice(1), mintValues, data), 'ERC1155InvalidArrayLength', - [tokenBatchIds.length - 1, mintAmounts.length], + [tokenBatchIds.length - 1, mintValues.length], ); }); context('with minted batch of tokens', function () { beforeEach(async function () { - this.receipt = await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts, data, { + this.receipt = await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues, data, { from: operator, }); }); @@ -105,7 +105,7 @@ contract('ERC1155', function (accounts) { ); for (let i = 0; i < holderBatchBalances.length; i++) { - expect(holderBatchBalances[i]).to.be.bignumber.equal(mintAmounts[i]); + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintValues[i]); } }); }); @@ -113,33 +113,33 @@ contract('ERC1155', function (accounts) { describe('_burn', function () { it("reverts when burning the zero account's tokens", async function () { - await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, tokenId, mintAmount), 'ERC1155InvalidSender', [ + await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, tokenId, mintValue), 'ERC1155InvalidSender', [ ZERO_ADDRESS, ]); }); it('reverts when burning a non-existent token id', async function () { await expectRevertCustomError( - this.token.$_burn(tokenHolder, tokenId, mintAmount), + this.token.$_burn(tokenHolder, tokenId, mintValue), 'ERC1155InsufficientBalance', - [tokenHolder, 0, mintAmount, tokenId], + [tokenHolder, 0, mintValue, tokenId], ); }); it('reverts when burning more than available tokens', async function () { - await this.token.$_mint(tokenHolder, tokenId, mintAmount, data, { from: operator }); + await this.token.$_mint(tokenHolder, tokenId, mintValue, data, { from: operator }); await expectRevertCustomError( - this.token.$_burn(tokenHolder, tokenId, mintAmount.addn(1)), + this.token.$_burn(tokenHolder, tokenId, mintValue.addn(1)), 'ERC1155InsufficientBalance', - [tokenHolder, mintAmount, mintAmount.addn(1), tokenId], + [tokenHolder, mintValue, mintValue.addn(1), tokenId], ); }); context('with minted-then-burnt tokens', function () { beforeEach(async function () { - await this.token.$_mint(tokenHolder, tokenId, mintAmount, data); - this.receipt = await this.token.$_burn(tokenHolder, tokenId, burnAmount, { from: operator }); + await this.token.$_mint(tokenHolder, tokenId, mintValue, data); + this.receipt = await this.token.$_burn(tokenHolder, tokenId, burnValue, { from: operator }); }); it('emits a TransferSingle event', function () { @@ -148,12 +148,12 @@ contract('ERC1155', function (accounts) { from: tokenHolder, to: ZERO_ADDRESS, id: tokenId, - value: burnAmount, + value: burnValue, }); }); it('accounts for both minting and burning', async function () { - expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintAmount.sub(burnAmount)); + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintValue.sub(burnValue)); }); }); }); @@ -161,7 +161,7 @@ contract('ERC1155', function (accounts) { describe('_burnBatch', function () { it("reverts when burning the zero account's tokens", async function () { await expectRevertCustomError( - this.token.$_burnBatch(ZERO_ADDRESS, tokenBatchIds, burnAmounts), + this.token.$_burnBatch(ZERO_ADDRESS, tokenBatchIds, burnValues), 'ERC1155InvalidSender', [ZERO_ADDRESS], ); @@ -169,30 +169,30 @@ contract('ERC1155', function (accounts) { it('reverts if length of inputs do not match', async function () { await expectRevertCustomError( - this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts.slice(1)), + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues.slice(1)), 'ERC1155InvalidArrayLength', - [tokenBatchIds.length, burnAmounts.length - 1], + [tokenBatchIds.length, burnValues.length - 1], ); await expectRevertCustomError( - this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds.slice(1), burnAmounts), + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds.slice(1), burnValues), 'ERC1155InvalidArrayLength', - [tokenBatchIds.length - 1, burnAmounts.length], + [tokenBatchIds.length - 1, burnValues.length], ); }); it('reverts when burning a non-existent token id', async function () { await expectRevertCustomError( - this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts), + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues), 'ERC1155InsufficientBalance', - [tokenBatchHolder, 0, tokenBatchIds[0], burnAmounts[0]], + [tokenBatchHolder, 0, tokenBatchIds[0], burnValues[0]], ); }); context('with minted-then-burnt tokens', function () { beforeEach(async function () { - await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts, data); - this.receipt = await this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts, { from: operator }); + await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues, data); + this.receipt = await this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues, { from: operator }); }); it('emits a TransferBatch event', function () { @@ -201,7 +201,7 @@ contract('ERC1155', function (accounts) { from: tokenBatchHolder, to: ZERO_ADDRESS, // ids: tokenBatchIds, - // values: burnAmounts, + // values: burnValues, }); }); @@ -212,7 +212,7 @@ contract('ERC1155', function (accounts) { ); for (let i = 0; i < holderBatchBalances.length; i++) { - expect(holderBatchBalances[i]).to.be.bignumber.equal(mintAmounts[i].sub(burnAmounts[i])); + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintValues[i].sub(burnValues[i])); } }); }); diff --git a/test/token/ERC1155/extensions/ERC1155Burnable.test.js b/test/token/ERC1155/extensions/ERC1155Burnable.test.js index 65a2f95f4..fc94db052 100644 --- a/test/token/ERC1155/extensions/ERC1155Burnable.test.js +++ b/test/token/ERC1155/extensions/ERC1155Burnable.test.js @@ -12,32 +12,32 @@ contract('ERC1155Burnable', function (accounts) { const uri = 'https://token.com'; const tokenIds = [new BN('42'), new BN('1137')]; - const amounts = [new BN('3000'), new BN('9902')]; + const values = [new BN('3000'), new BN('9902')]; beforeEach(async function () { this.token = await ERC1155Burnable.new(uri); - await this.token.$_mint(holder, tokenIds[0], amounts[0], '0x'); - await this.token.$_mint(holder, tokenIds[1], amounts[1], '0x'); + await this.token.$_mint(holder, tokenIds[0], values[0], '0x'); + await this.token.$_mint(holder, tokenIds[1], values[1], '0x'); }); describe('burn', function () { it('holder can burn their tokens', async function () { - await this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: holder }); + await this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: holder }); expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); }); it("approved operators can burn the holder's tokens", async function () { await this.token.setApprovalForAll(operator, true, { from: holder }); - await this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: operator }); + await this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: operator }); expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); }); it("unapproved accounts cannot burn the holder's tokens", async function () { await expectRevertCustomError( - this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: other }), + this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: other }), 'ERC1155MissingApprovalForAll', [other, holder], ); @@ -46,7 +46,7 @@ contract('ERC1155Burnable', function (accounts) { describe('burnBatch', function () { it('holder can burn their tokens', async function () { - await this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: holder }); + await this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: holder }); expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); @@ -54,7 +54,7 @@ contract('ERC1155Burnable', function (accounts) { it("approved operators can burn the holder's tokens", async function () { await this.token.setApprovalForAll(operator, true, { from: holder }); - await this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: operator }); + await this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: operator }); expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); @@ -62,7 +62,7 @@ contract('ERC1155Burnable', function (accounts) { it("unapproved accounts cannot burn the holder's tokens", async function () { await expectRevertCustomError( - this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: other }), + this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: other }), 'ERC1155MissingApprovalForAll', [other, holder], ); diff --git a/test/token/ERC1155/extensions/ERC1155Pausable.test.js b/test/token/ERC1155/extensions/ERC1155Pausable.test.js index b0ac54bdb..248ea5684 100644 --- a/test/token/ERC1155/extensions/ERC1155Pausable.test.js +++ b/test/token/ERC1155/extensions/ERC1155Pausable.test.js @@ -16,21 +16,21 @@ contract('ERC1155Pausable', function (accounts) { context('when token is paused', function () { const firstTokenId = new BN('37'); - const firstTokenAmount = new BN('42'); + const firstTokenValue = new BN('42'); const secondTokenId = new BN('19842'); - const secondTokenAmount = new BN('23'); + const secondTokenValue = new BN('23'); beforeEach(async function () { await this.token.setApprovalForAll(operator, true, { from: holder }); - await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); await this.token.$_pause(); }); it('reverts when trying to safeTransferFrom from holder', async function () { await expectRevertCustomError( - this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenAmount, '0x', { from: holder }), + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenValue, '0x', { from: holder }), 'EnforcedPause', [], ); @@ -38,7 +38,7 @@ contract('ERC1155Pausable', function (accounts) { it('reverts when trying to safeTransferFrom from operator', async function () { await expectRevertCustomError( - this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenAmount, '0x', { from: operator }), + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenValue, '0x', { from: operator }), 'EnforcedPause', [], ); @@ -46,7 +46,7 @@ contract('ERC1155Pausable', function (accounts) { it('reverts when trying to safeBatchTransferFrom from holder', async function () { await expectRevertCustomError( - this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenAmount], '0x', { from: holder }), + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenValue], '0x', { from: holder }), 'EnforcedPause', [], ); @@ -54,7 +54,7 @@ contract('ERC1155Pausable', function (accounts) { it('reverts when trying to safeBatchTransferFrom from operator', async function () { await expectRevertCustomError( - this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenAmount], '0x', { + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenValue], '0x', { from: operator, }), 'EnforcedPause', @@ -64,7 +64,7 @@ contract('ERC1155Pausable', function (accounts) { it('reverts when trying to mint', async function () { await expectRevertCustomError( - this.token.$_mint(holder, secondTokenId, secondTokenAmount, '0x'), + this.token.$_mint(holder, secondTokenId, secondTokenValue, '0x'), 'EnforcedPause', [], ); @@ -72,19 +72,19 @@ contract('ERC1155Pausable', function (accounts) { it('reverts when trying to mintBatch', async function () { await expectRevertCustomError( - this.token.$_mintBatch(holder, [secondTokenId], [secondTokenAmount], '0x'), + this.token.$_mintBatch(holder, [secondTokenId], [secondTokenValue], '0x'), 'EnforcedPause', [], ); }); it('reverts when trying to burn', async function () { - await expectRevertCustomError(this.token.$_burn(holder, firstTokenId, firstTokenAmount), 'EnforcedPause', []); + await expectRevertCustomError(this.token.$_burn(holder, firstTokenId, firstTokenValue), 'EnforcedPause', []); }); it('reverts when trying to burnBatch', async function () { await expectRevertCustomError( - this.token.$_burnBatch(holder, [firstTokenId], [firstTokenAmount]), + this.token.$_burnBatch(holder, [firstTokenId], [firstTokenValue]), 'EnforcedPause', [], ); @@ -98,9 +98,9 @@ contract('ERC1155Pausable', function (accounts) { }); describe('balanceOf', function () { - it('returns the amount of tokens owned by the given address', async function () { + it('returns the token value owned by the given address', async function () { const balance = await this.token.balanceOf(holder, firstTokenId); - expect(balance).to.be.bignumber.equal(firstTokenAmount); + expect(balance).to.be.bignumber.equal(firstTokenValue); }); }); diff --git a/test/token/ERC1155/extensions/ERC1155Supply.test.js b/test/token/ERC1155/extensions/ERC1155Supply.test.js index 22a75c84f..bf86920f6 100644 --- a/test/token/ERC1155/extensions/ERC1155Supply.test.js +++ b/test/token/ERC1155/extensions/ERC1155Supply.test.js @@ -12,10 +12,10 @@ contract('ERC1155Supply', function (accounts) { const uri = 'https://token.com'; const firstTokenId = new BN('37'); - const firstTokenAmount = new BN('42'); + const firstTokenValue = new BN('42'); const secondTokenId = new BN('19842'); - const secondTokenAmount = new BN('23'); + const secondTokenValue = new BN('23'); beforeEach(async function () { this.token = await ERC1155Supply.new(uri); @@ -35,7 +35,7 @@ contract('ERC1155Supply', function (accounts) { context('after mint', function () { context('single', function () { beforeEach(async function () { - await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); }); it('exist', async function () { @@ -43,19 +43,14 @@ contract('ERC1155Supply', function (accounts) { }); it('totalSupply', async function () { - expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenAmount); - expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal(firstTokenAmount); + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenValue); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal(firstTokenValue); }); }); context('batch', function () { beforeEach(async function () { - await this.token.$_mintBatch( - holder, - [firstTokenId, secondTokenId], - [firstTokenAmount, secondTokenAmount], - '0x', - ); + await this.token.$_mintBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue], '0x'); }); it('exist', async function () { @@ -64,12 +59,10 @@ contract('ERC1155Supply', function (accounts) { }); it('totalSupply', async function () { - expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenAmount); - expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal( - secondTokenAmount, - ); + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenValue); + expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal(secondTokenValue); expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal( - firstTokenAmount.add(secondTokenAmount), + firstTokenValue.add(secondTokenValue), ); }); }); @@ -78,8 +71,8 @@ contract('ERC1155Supply', function (accounts) { context('after burn', function () { context('single', function () { beforeEach(async function () { - await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); - await this.token.$_burn(holder, firstTokenId, firstTokenAmount); + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_burn(holder, firstTokenId, firstTokenValue); }); it('exist', async function () { @@ -94,13 +87,8 @@ contract('ERC1155Supply', function (accounts) { context('batch', function () { beforeEach(async function () { - await this.token.$_mintBatch( - holder, - [firstTokenId, secondTokenId], - [firstTokenAmount, secondTokenAmount], - '0x', - ); - await this.token.$_burnBatch(holder, [firstTokenId, secondTokenId], [firstTokenAmount, secondTokenAmount]); + await this.token.$_mintBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue], '0x'); + await this.token.$_burnBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue]); }); it('exist', async function () { @@ -118,7 +106,7 @@ contract('ERC1155Supply', function (accounts) { context('other', function () { it('supply unaffected by no-op', async function () { - this.token.safeTransferFrom(ZERO_ADDRESS, ZERO_ADDRESS, firstTokenId, firstTokenAmount, '0x', { + this.token.safeTransferFrom(ZERO_ADDRESS, ZERO_ADDRESS, firstTokenId, firstTokenValue, '0x', { from: ZERO_ADDRESS, }); expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); diff --git a/test/token/ERC1155/extensions/ERC1155URIStorage.test.js b/test/token/ERC1155/extensions/ERC1155URIStorage.test.js index 95d9c18f7..58ac67bc6 100644 --- a/test/token/ERC1155/extensions/ERC1155URIStorage.test.js +++ b/test/token/ERC1155/extensions/ERC1155URIStorage.test.js @@ -12,14 +12,14 @@ contract(['ERC1155URIStorage'], function (accounts) { const baseUri = 'https://token.com/'; const tokenId = new BN('1'); - const amount = new BN('3000'); + const value = new BN('3000'); describe('with base uri set', function () { beforeEach(async function () { this.token = await ERC1155URIStorage.new(erc1155Uri); await this.token.$_setBaseURI(baseUri); - await this.token.$_mint(holder, tokenId, amount, '0x'); + await this.token.$_mint(holder, tokenId, value, '0x'); }); it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { @@ -44,7 +44,7 @@ contract(['ERC1155URIStorage'], function (accounts) { beforeEach(async function () { this.token = await ERC1155URIStorage.new(''); - await this.token.$_mint(holder, tokenId, amount, '0x'); + await this.token.$_mint(holder, tokenId, value, '0x'); }); it('can request the token uri, returning an empty string if no token uri was set', async function () { diff --git a/test/token/ERC1155/utils/ERC1155Holder.test.js b/test/token/ERC1155/utils/ERC1155Holder.test.js index 8d8541640..ee818eae8 100644 --- a/test/token/ERC1155/utils/ERC1155Holder.test.js +++ b/test/token/ERC1155/utils/ERC1155Holder.test.js @@ -11,13 +11,13 @@ contract('ERC1155Holder', function (accounts) { const [creator] = accounts; const uri = 'https://token-cdn-domain/{id}.json'; const multiTokenIds = [new BN(1), new BN(2), new BN(3)]; - const multiTokenAmounts = [new BN(1000), new BN(2000), new BN(3000)]; + const multiTokenValues = [new BN(1000), new BN(2000), new BN(3000)]; const transferData = '0x12345678'; beforeEach(async function () { this.multiToken = await ERC1155.new(uri); this.holder = await ERC1155Holder.new(); - await this.multiToken.$_mintBatch(creator, multiTokenIds, multiTokenAmounts, '0x'); + await this.multiToken.$_mintBatch(creator, multiTokenIds, multiTokenValues, '0x'); }); shouldSupportInterfaces(['ERC165', 'ERC1155Receiver']); @@ -27,13 +27,13 @@ contract('ERC1155Holder', function (accounts) { creator, this.holder.address, multiTokenIds[0], - multiTokenAmounts[0], + multiTokenValues[0], transferData, { from: creator }, ); expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[0])).to.be.bignumber.equal( - multiTokenAmounts[0], + multiTokenValues[0], ); for (let i = 1; i < multiTokenIds.length; i++) { @@ -50,14 +50,14 @@ contract('ERC1155Holder', function (accounts) { creator, this.holder.address, multiTokenIds, - multiTokenAmounts, + multiTokenValues, transferData, { from: creator }, ); for (let i = 0; i < multiTokenIds.length; i++) { expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal( - multiTokenAmounts[i], + multiTokenValues[i], ); } }); diff --git a/test/token/ERC20/ERC20.behavior.js b/test/token/ERC20/ERC20.behavior.js index bb2efda89..b6f8617b2 100644 --- a/test/token/ERC20/ERC20.behavior.js +++ b/test/token/ERC20/ERC20.behavior.js @@ -9,7 +9,7 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { const { forcedApproval } = opts; describe('total supply', function () { - it('returns the total amount of tokens', async function () { + it('returns the total token value', async function () { expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); }); }); @@ -22,7 +22,7 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { }); describe('when the requested account has some tokens', function () { - it('returns the total amount of tokens', async function () { + it('returns the total token value', async function () { expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(initialSupply); }); }); @@ -49,33 +49,33 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { }); describe('when the token owner has enough balance', function () { - const amount = initialSupply; + const value = initialSupply; - it('transfers the requested amount', async function () { - await this.token.transferFrom(tokenOwner, to, amount, { from: spender }); + it('transfers the requested value', async function () { + await this.token.transferFrom(tokenOwner, to, value, { from: spender }); expect(await this.token.balanceOf(tokenOwner)).to.be.bignumber.equal('0'); - expect(await this.token.balanceOf(to)).to.be.bignumber.equal(amount); + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(value); }); it('decreases the spender allowance', async function () { - await this.token.transferFrom(tokenOwner, to, amount, { from: spender }); + await this.token.transferFrom(tokenOwner, to, value, { from: spender }); expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal('0'); }); it('emits a transfer event', async function () { - expectEvent(await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'Transfer', { + expectEvent(await this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'Transfer', { from: tokenOwner, to: to, - value: amount, + value: value, }); }); if (forcedApproval) { it('emits an approval event', async function () { - expectEvent(await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'Approval', { + expectEvent(await this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'Approval', { owner: tokenOwner, spender: spender, value: await this.token.allowance(tokenOwner, spender), @@ -84,7 +84,7 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { } else { it('does not emit an approval event', async function () { expectEvent.notEmitted( - await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + await this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'Approval', ); }); @@ -92,7 +92,7 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { }); describe('when the token owner does not have enough balance', function () { - const amount = initialSupply; + const value = initialSupply; beforeEach('reducing balance', async function () { await this.token.transfer(to, 1, { from: tokenOwner }); @@ -100,9 +100,9 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { it('reverts', async function () { await expectRevertCustomError( - this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'ERC20InsufficientBalance', - [tokenOwner, amount - 1, amount], + [tokenOwner, value - 1, value], ); }); }); @@ -116,19 +116,19 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { }); describe('when the token owner has enough balance', function () { - const amount = initialSupply; + const value = initialSupply; it('reverts', async function () { await expectRevertCustomError( - this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'ERC20InsufficientAllowance', - [spender, allowance, amount], + [spender, allowance, value], ); }); }); describe('when the token owner does not have enough balance', function () { - const amount = allowance; + const value = allowance; beforeEach('reducing balance', async function () { await this.token.transfer(to, 2, { from: tokenOwner }); @@ -136,9 +136,9 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { it('reverts', async function () { await expectRevertCustomError( - this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'ERC20InsufficientBalance', - [tokenOwner, amount - 1, amount], + [tokenOwner, value - 1, value], ); }); }); @@ -162,16 +162,16 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { }); describe('when the recipient is the zero address', function () { - const amount = initialSupply; + const value = initialSupply; const to = ZERO_ADDRESS; beforeEach(async function () { - await this.token.approve(spender, amount, { from: tokenOwner }); + await this.token.approve(spender, value, { from: tokenOwner }); }); it('reverts', async function () { await expectRevertCustomError( - this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'ERC20InvalidReceiver', [ZERO_ADDRESS], ); @@ -180,13 +180,13 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { }); describe('when the token owner is the zero address', function () { - const amount = 0; + const value = 0; const tokenOwner = ZERO_ADDRESS; const to = recipient; it('reverts', async function () { await expectRevertCustomError( - this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'ERC20InvalidApprover', [ZERO_ADDRESS], ); @@ -195,8 +195,8 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { }); describe('approve', function () { - shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, amount) { - return this.token.approve(spender, amount, { from: owner }); + shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, value) { + return this.token.approve(spender, value, { from: owner }); }); }); } @@ -204,38 +204,38 @@ function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { function shouldBehaveLikeERC20Transfer(from, to, balance, transfer) { describe('when the recipient is not the zero address', function () { describe('when the sender does not have enough balance', function () { - const amount = balance.addn(1); + const value = balance.addn(1); it('reverts', async function () { - await expectRevertCustomError(transfer.call(this, from, to, amount), 'ERC20InsufficientBalance', [ + await expectRevertCustomError(transfer.call(this, from, to, value), 'ERC20InsufficientBalance', [ from, balance, - amount, + value, ]); }); }); describe('when the sender transfers all balance', function () { - const amount = balance; + const value = balance; - it('transfers the requested amount', async function () { - await transfer.call(this, from, to, amount); + it('transfers the requested value', async function () { + await transfer.call(this, from, to, value); expect(await this.token.balanceOf(from)).to.be.bignumber.equal('0'); - expect(await this.token.balanceOf(to)).to.be.bignumber.equal(amount); + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(value); }); it('emits a transfer event', async function () { - expectEvent(await transfer.call(this, from, to, amount), 'Transfer', { from, to, value: amount }); + expectEvent(await transfer.call(this, from, to, value), 'Transfer', { from, to, value: value }); }); }); describe('when the sender transfers zero tokens', function () { - const amount = new BN('0'); + const value = new BN('0'); - it('transfers the requested amount', async function () { - await transfer.call(this, from, to, amount); + it('transfers the requested value', async function () { + await transfer.call(this, from, to, value); expect(await this.token.balanceOf(from)).to.be.bignumber.equal(balance); @@ -243,7 +243,7 @@ function shouldBehaveLikeERC20Transfer(from, to, balance, transfer) { }); it('emits a transfer event', async function () { - expectEvent(await transfer.call(this, from, to, amount), 'Transfer', { from, to, value: amount }); + expectEvent(await transfer.call(this, from, to, value), 'Transfer', { from, to, value: value }); }); }); }); @@ -260,65 +260,65 @@ function shouldBehaveLikeERC20Transfer(from, to, balance, transfer) { function shouldBehaveLikeERC20Approve(owner, spender, supply, approve) { describe('when the spender is not the zero address', function () { describe('when the sender has enough balance', function () { - const amount = supply; + const value = supply; it('emits an approval event', async function () { - expectEvent(await approve.call(this, owner, spender, amount), 'Approval', { + expectEvent(await approve.call(this, owner, spender, value), 'Approval', { owner: owner, spender: spender, - value: amount, + value: value, }); }); - describe('when there was no approved amount before', function () { - it('approves the requested amount', async function () { - await approve.call(this, owner, spender, amount); + describe('when there was no approved value before', function () { + it('approves the requested value', async function () { + await approve.call(this, owner, spender, value); - expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); }); }); - describe('when the spender had an approved amount', function () { + describe('when the spender had an approved value', function () { beforeEach(async function () { await approve.call(this, owner, spender, new BN(1)); }); - it('approves the requested amount and replaces the previous one', async function () { - await approve.call(this, owner, spender, amount); + it('approves the requested value and replaces the previous one', async function () { + await approve.call(this, owner, spender, value); - expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); }); }); }); describe('when the sender does not have enough balance', function () { - const amount = supply.addn(1); + const value = supply.addn(1); it('emits an approval event', async function () { - expectEvent(await approve.call(this, owner, spender, amount), 'Approval', { + expectEvent(await approve.call(this, owner, spender, value), 'Approval', { owner: owner, spender: spender, - value: amount, + value: value, }); }); - describe('when there was no approved amount before', function () { - it('approves the requested amount', async function () { - await approve.call(this, owner, spender, amount); + describe('when there was no approved value before', function () { + it('approves the requested value', async function () { + await approve.call(this, owner, spender, value); - expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); }); }); - describe('when the spender had an approved amount', function () { + describe('when the spender had an approved value', function () { beforeEach(async function () { await approve.call(this, owner, spender, new BN(1)); }); - it('approves the requested amount and replaces the previous one', async function () { - await approve.call(this, owner, spender, amount); + it('approves the requested value and replaces the previous one', async function () { + await approve.call(this, owner, spender, value); - expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); }); }); }); diff --git a/test/token/ERC20/ERC20.test.js b/test/token/ERC20/ERC20.test.js index ef6d82f2b..a63df5239 100644 --- a/test/token/ERC20/ERC20.test.js +++ b/test/token/ERC20/ERC20.test.js @@ -46,145 +46,145 @@ contract('ERC20', function (accounts) { describe('when the spender is not the zero address', function () { const spender = recipient; - function shouldDecreaseApproval(amount) { - describe('when there was no approved amount before', function () { + function shouldDecreaseApproval(value) { + describe('when there was no approved value before', function () { it('reverts', async function () { const allowance = await this.token.allowance(initialHolder, spender); await expectRevertCustomError( - this.token.decreaseAllowance(spender, amount, { from: initialHolder }), + this.token.decreaseAllowance(spender, value, { from: initialHolder }), 'ERC20FailedDecreaseAllowance', - [spender, allowance, amount], + [spender, allowance, value], ); }); }); - describe('when the spender had an approved amount', function () { - const approvedAmount = amount; + describe('when the spender had an approved value', function () { + const approvedValue = value; beforeEach(async function () { - await this.token.approve(spender, approvedAmount, { from: initialHolder }); + await this.token.approve(spender, approvedValue, { from: initialHolder }); }); it('emits an approval event', async function () { expectEvent( - await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }), + await this.token.decreaseAllowance(spender, approvedValue, { from: initialHolder }), 'Approval', { owner: initialHolder, spender: spender, value: new BN(0) }, ); }); - it('decreases the spender allowance subtracting the requested amount', async function () { - await this.token.decreaseAllowance(spender, approvedAmount.subn(1), { from: initialHolder }); + it('decreases the spender allowance subtracting the requested value', async function () { + await this.token.decreaseAllowance(spender, approvedValue.subn(1), { from: initialHolder }); expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('1'); }); it('sets the allowance to zero when all allowance is removed', async function () { - await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }); + await this.token.decreaseAllowance(spender, approvedValue, { from: initialHolder }); expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('0'); }); it('reverts when more than the full allowance is removed', async function () { await expectRevertCustomError( - this.token.decreaseAllowance(spender, approvedAmount.addn(1), { from: initialHolder }), + this.token.decreaseAllowance(spender, approvedValue.addn(1), { from: initialHolder }), 'ERC20FailedDecreaseAllowance', - [spender, approvedAmount, approvedAmount.addn(1)], + [spender, approvedValue, approvedValue.addn(1)], ); }); }); } describe('when the sender has enough balance', function () { - const amount = initialSupply; + const value = initialSupply; - shouldDecreaseApproval(amount); + shouldDecreaseApproval(value); }); describe('when the sender does not have enough balance', function () { - const amount = initialSupply.addn(1); + const value = initialSupply.addn(1); - shouldDecreaseApproval(amount); + shouldDecreaseApproval(value); }); }); describe('when the spender is the zero address', function () { - const amount = initialSupply; + const value = initialSupply; const spender = ZERO_ADDRESS; it('reverts', async function () { await expectRevertCustomError( - this.token.decreaseAllowance(spender, amount, { from: initialHolder }), + this.token.decreaseAllowance(spender, value, { from: initialHolder }), 'ERC20FailedDecreaseAllowance', - [spender, 0, amount], + [spender, 0, value], ); }); }); }); describe('increase allowance', function () { - const amount = initialSupply; + const value = initialSupply; describe('when the spender is not the zero address', function () { const spender = recipient; describe('when the sender has enough balance', function () { it('emits an approval event', async function () { - expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', { + expectEvent(await this.token.increaseAllowance(spender, value, { from: initialHolder }), 'Approval', { owner: initialHolder, spender: spender, - value: amount, + value: value, }); }); - describe('when there was no approved amount before', function () { - it('approves the requested amount', async function () { - await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + describe('when there was no approved value before', function () { + it('approves the requested value', async function () { + await this.token.increaseAllowance(spender, value, { from: initialHolder }); - expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount); + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(value); }); }); - describe('when the spender had an approved amount', function () { + describe('when the spender had an approved value', function () { beforeEach(async function () { await this.token.approve(spender, new BN(1), { from: initialHolder }); }); - it('increases the spender allowance adding the requested amount', async function () { - await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + it('increases the spender allowance adding the requested value', async function () { + await this.token.increaseAllowance(spender, value, { from: initialHolder }); - expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1)); + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(value.addn(1)); }); }); }); describe('when the sender does not have enough balance', function () { - const amount = initialSupply.addn(1); + const value = initialSupply.addn(1); it('emits an approval event', async function () { - expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', { + expectEvent(await this.token.increaseAllowance(spender, value, { from: initialHolder }), 'Approval', { owner: initialHolder, spender: spender, - value: amount, + value: value, }); }); - describe('when there was no approved amount before', function () { - it('approves the requested amount', async function () { - await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + describe('when there was no approved value before', function () { + it('approves the requested value', async function () { + await this.token.increaseAllowance(spender, value, { from: initialHolder }); - expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount); + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(value); }); }); - describe('when the spender had an approved amount', function () { + describe('when the spender had an approved value', function () { beforeEach(async function () { await this.token.approve(spender, new BN(1), { from: initialHolder }); }); - it('increases the spender allowance adding the requested amount', async function () { - await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + it('increases the spender allowance adding the requested value', async function () { + await this.token.increaseAllowance(spender, value, { from: initialHolder }); - expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1)); + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(value.addn(1)); }); }); }); @@ -195,7 +195,7 @@ contract('ERC20', function (accounts) { it('reverts', async function () { await expectRevertCustomError( - this.token.increaseAllowance(spender, amount, { from: initialHolder }), + this.token.increaseAllowance(spender, value, { from: initialHolder }), 'ERC20InvalidSpender', [ZERO_ADDRESS], ); @@ -204,11 +204,9 @@ contract('ERC20', function (accounts) { }); describe('_mint', function () { - const amount = new BN(50); + const value = new BN(50); it('rejects a null account', async function () { - await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, amount), 'ERC20InvalidReceiver', [ - ZERO_ADDRESS, - ]); + await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, value), 'ERC20InvalidReceiver', [ZERO_ADDRESS]); }); it('rejects overflow', async function () { @@ -221,22 +219,22 @@ contract('ERC20', function (accounts) { describe('for a non zero account', function () { beforeEach('minting', async function () { - this.receipt = await this.token.$_mint(recipient, amount); + this.receipt = await this.token.$_mint(recipient, value); }); it('increments totalSupply', async function () { - const expectedSupply = initialSupply.add(amount); + const expectedSupply = initialSupply.add(value); expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); }); it('increments recipient balance', async function () { - expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); }); it('emits Transfer event', async function () { const event = expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: recipient }); - expect(event.args.value).to.be.bignumber.equal(amount); + expect(event.args.value).to.be.bignumber.equal(value); }); }); }); @@ -257,81 +255,81 @@ contract('ERC20', function (accounts) { ); }); - const describeBurn = function (description, amount) { + const describeBurn = function (description, value) { describe(description, function () { beforeEach('burning', async function () { - this.receipt = await this.token.$_burn(initialHolder, amount); + this.receipt = await this.token.$_burn(initialHolder, value); }); it('decrements totalSupply', async function () { - const expectedSupply = initialSupply.sub(amount); + const expectedSupply = initialSupply.sub(value); expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); }); it('decrements initialHolder balance', async function () { - const expectedBalance = initialSupply.sub(amount); + const expectedBalance = initialSupply.sub(value); expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(expectedBalance); }); it('emits Transfer event', async function () { const event = expectEvent(this.receipt, 'Transfer', { from: initialHolder, to: ZERO_ADDRESS }); - expect(event.args.value).to.be.bignumber.equal(amount); + expect(event.args.value).to.be.bignumber.equal(value); }); }); }; describeBurn('for entire balance', initialSupply); - describeBurn('for less amount than balance', initialSupply.subn(1)); + describeBurn('for less value than balance', initialSupply.subn(1)); }); }); describe('_update', function () { - const amount = new BN(1); + const value = new BN(1); it('from is the zero address', async function () { const balanceBefore = await this.token.balanceOf(initialHolder); const totalSupply = await this.token.totalSupply(); - expectEvent(await this.token.$_update(ZERO_ADDRESS, initialHolder, amount), 'Transfer', { + expectEvent(await this.token.$_update(ZERO_ADDRESS, initialHolder, value), 'Transfer', { from: ZERO_ADDRESS, to: initialHolder, - value: amount, + value: value, }); - expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.add(amount)); - expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.add(amount)); + expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.add(value)); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.add(value)); }); it('to is the zero address', async function () { const balanceBefore = await this.token.balanceOf(initialHolder); const totalSupply = await this.token.totalSupply(); - expectEvent(await this.token.$_update(initialHolder, ZERO_ADDRESS, amount), 'Transfer', { + expectEvent(await this.token.$_update(initialHolder, ZERO_ADDRESS, value), 'Transfer', { from: initialHolder, to: ZERO_ADDRESS, - value: amount, + value: value, }); - expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.sub(amount)); - expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.sub(amount)); + expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.sub(value)); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.sub(value)); }); it('from and to are the zero address', async function () { const totalSupply = await this.token.totalSupply(); - await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, amount); + await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, value); expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply); - expectEvent(await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, amount), 'Transfer', { + expectEvent(await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, value), 'Transfer', { from: ZERO_ADDRESS, to: ZERO_ADDRESS, - value: amount, + value: value, }); }); }); describe('_transfer', function () { - shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, amount) { - return this.token.$_transfer(from, to, amount); + shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, value) { + return this.token.$_transfer(from, to, value); }); describe('when the sender is the zero address', function () { @@ -346,8 +344,8 @@ contract('ERC20', function (accounts) { }); describe('_approve', function () { - shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, amount) { - return this.token.$_approve(owner, spender, amount); + shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, value) { + return this.token.$_approve(owner, spender, value); }); describe('when the owner is the zero address', function () { diff --git a/test/token/ERC20/extensions/ERC20Burnable.behavior.js b/test/token/ERC20/extensions/ERC20Burnable.behavior.js index 848e54b79..937491bdf 100644 --- a/test/token/ERC20/extensions/ERC20Burnable.behavior.js +++ b/test/token/ERC20/extensions/ERC20Burnable.behavior.js @@ -6,42 +6,42 @@ const { expectRevertCustomError } = require('../../../helpers/customError'); function shouldBehaveLikeERC20Burnable(owner, initialBalance, [burner]) { describe('burn', function () { - describe('when the given amount is not greater than balance of the sender', function () { - context('for a zero amount', function () { + describe('when the given value is not greater than balance of the sender', function () { + context('for a zero value', function () { shouldBurn(new BN(0)); }); - context('for a non-zero amount', function () { + context('for a non-zero value', function () { shouldBurn(new BN(100)); }); - function shouldBurn(amount) { + function shouldBurn(value) { beforeEach(async function () { - this.receipt = await this.token.burn(amount, { from: owner }); + this.receipt = await this.token.burn(value, { from: owner }); }); - it('burns the requested amount', async function () { - expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(amount)); + it('burns the requested value', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(value)); }); it('emits a transfer event', async function () { expectEvent(this.receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, - value: amount, + value: value, }); }); } }); - describe('when the given amount is greater than the balance of the sender', function () { - const amount = initialBalance.addn(1); + describe('when the given value is greater than the balance of the sender', function () { + const value = initialBalance.addn(1); it('reverts', async function () { - await expectRevertCustomError(this.token.burn(amount, { from: owner }), 'ERC20InsufficientBalance', [ + await expectRevertCustomError(this.token.burn(value, { from: owner }), 'ERC20InsufficientBalance', [ owner, initialBalance, - amount, + value, ]); }); }); @@ -49,54 +49,54 @@ function shouldBehaveLikeERC20Burnable(owner, initialBalance, [burner]) { describe('burnFrom', function () { describe('on success', function () { - context('for a zero amount', function () { + context('for a zero value', function () { shouldBurnFrom(new BN(0)); }); - context('for a non-zero amount', function () { + context('for a non-zero value', function () { shouldBurnFrom(new BN(100)); }); - function shouldBurnFrom(amount) { - const originalAllowance = amount.muln(3); + function shouldBurnFrom(value) { + const originalAllowance = value.muln(3); beforeEach(async function () { await this.token.approve(burner, originalAllowance, { from: owner }); - this.receipt = await this.token.burnFrom(owner, amount, { from: burner }); + this.receipt = await this.token.burnFrom(owner, value, { from: burner }); }); - it('burns the requested amount', async function () { - expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(amount)); + it('burns the requested value', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(value)); }); it('decrements allowance', async function () { - expect(await this.token.allowance(owner, burner)).to.be.bignumber.equal(originalAllowance.sub(amount)); + expect(await this.token.allowance(owner, burner)).to.be.bignumber.equal(originalAllowance.sub(value)); }); it('emits a transfer event', async function () { expectEvent(this.receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, - value: amount, + value: value, }); }); } }); - describe('when the given amount is greater than the balance of the sender', function () { - const amount = initialBalance.addn(1); + describe('when the given value is greater than the balance of the sender', function () { + const value = initialBalance.addn(1); it('reverts', async function () { - await this.token.approve(burner, amount, { from: owner }); - await expectRevertCustomError( - this.token.burnFrom(owner, amount, { from: burner }), - 'ERC20InsufficientBalance', - [owner, initialBalance, amount], - ); + await this.token.approve(burner, value, { from: owner }); + await expectRevertCustomError(this.token.burnFrom(owner, value, { from: burner }), 'ERC20InsufficientBalance', [ + owner, + initialBalance, + value, + ]); }); }); - describe('when the given amount is greater than the allowance', function () { + describe('when the given value is greater than the allowance', function () { const allowance = new BN(100); it('reverts', async function () { diff --git a/test/token/ERC20/extensions/ERC20Capped.behavior.js b/test/token/ERC20/extensions/ERC20Capped.behavior.js index c40e4fcc4..5af5c3ddc 100644 --- a/test/token/ERC20/extensions/ERC20Capped.behavior.js +++ b/test/token/ERC20/extensions/ERC20Capped.behavior.js @@ -9,12 +9,12 @@ function shouldBehaveLikeERC20Capped(accounts, cap) { expect(await this.token.cap()).to.be.bignumber.equal(cap); }); - it('mints when amount is less than cap', async function () { + it('mints when value is less than cap', async function () { await this.token.$_mint(user, cap.subn(1)); expect(await this.token.totalSupply()).to.be.bignumber.equal(cap.subn(1)); }); - it('fails to mint if the amount exceeds the cap', async function () { + it('fails to mint if the value exceeds the cap', async function () { await this.token.$_mint(user, cap.subn(1)); await expectRevertCustomError(this.token.$_mint(user, 2), 'ERC20ExceededCap', [cap.addn(1), cap]); }); diff --git a/test/token/ERC20/extensions/ERC20FlashMint.test.js b/test/token/ERC20/extensions/ERC20FlashMint.test.js index a646704e2..13d5b3ef4 100644 --- a/test/token/ERC20/extensions/ERC20FlashMint.test.js +++ b/test/token/ERC20/extensions/ERC20FlashMint.test.js @@ -15,7 +15,7 @@ contract('ERC20FlashMint', function (accounts) { const symbol = 'MTKN'; const initialSupply = new BN(100); - const loanAmount = new BN(10000000000000); + const loanValue = new BN(10000000000000); beforeEach(async function () { this.token = await ERC20FlashMintMock.new(name, symbol); @@ -34,11 +34,11 @@ contract('ERC20FlashMint', function (accounts) { describe('flashFee', function () { it('token match', async function () { - expect(await this.token.flashFee(this.token.address, loanAmount)).to.be.bignumber.equal('0'); + expect(await this.token.flashFee(this.token.address, loanValue)).to.be.bignumber.equal('0'); }); it('token mismatch', async function () { - await expectRevertCustomError(this.token.flashFee(ZERO_ADDRESS, loanAmount), 'ERC3156UnsupportedToken', [ + await expectRevertCustomError(this.token.flashFee(ZERO_ADDRESS, loanValue), 'ERC3156UnsupportedToken', [ ZERO_ADDRESS, ]); }); @@ -53,26 +53,26 @@ contract('ERC20FlashMint', function (accounts) { describe('flashLoan', function () { it('success', async function () { const receiver = await ERC3156FlashBorrowerMock.new(true, true); - const { tx } = await this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'); + const { tx } = await this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: ZERO_ADDRESS, to: receiver.address, - value: loanAmount, + value: loanValue, }); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: receiver.address, to: ZERO_ADDRESS, - value: loanAmount, + value: loanValue, }); await expectEvent.inTransaction(tx, receiver, 'BalanceOf', { token: this.token.address, account: receiver.address, - value: loanAmount, + value: loanValue, }); await expectEvent.inTransaction(tx, receiver, 'TotalSupply', { token: this.token.address, - value: initialSupply.add(loanAmount), + value: initialSupply.add(loanValue), }); expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); @@ -83,7 +83,7 @@ contract('ERC20FlashMint', function (accounts) { it('missing return value', async function () { const receiver = await ERC3156FlashBorrowerMock.new(false, true); await expectRevertCustomError( - this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'), + this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'), 'ERC3156InvalidReceiver', [receiver.address], ); @@ -92,9 +92,9 @@ contract('ERC20FlashMint', function (accounts) { it('missing approval', async function () { const receiver = await ERC3156FlashBorrowerMock.new(true, false); await expectRevertCustomError( - this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'), + this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'), 'ERC20InsufficientAllowance', - [this.token.address, 0, loanAmount], + [this.token.address, 0, loanValue], ); }); @@ -102,9 +102,9 @@ contract('ERC20FlashMint', function (accounts) { const receiver = await ERC3156FlashBorrowerMock.new(true, true); const data = this.token.contract.methods.transfer(other, 10).encodeABI(); await expectRevertCustomError( - this.token.flashLoan(receiver.address, this.token.address, loanAmount, data), + this.token.flashLoan(receiver.address, this.token.address, loanValue, data), 'ERC20InsufficientBalance', - [receiver.address, loanAmount - 10, loanAmount], + [receiver.address, loanValue - 10, loanValue], ); }); @@ -130,29 +130,29 @@ contract('ERC20FlashMint', function (accounts) { expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal(receiverInitialBalance); await this.token.setFlashFee(flashFee); - expect(await this.token.flashFee(this.token.address, loanAmount)).to.be.bignumber.equal(flashFee); + expect(await this.token.flashFee(this.token.address, loanValue)).to.be.bignumber.equal(flashFee); }); it('default flash fee receiver', async function () { - const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanAmount, '0x'); + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanValue, '0x'); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: ZERO_ADDRESS, to: this.receiver.address, - value: loanAmount, + value: loanValue, }); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.receiver.address, to: ZERO_ADDRESS, - value: loanAmount.add(flashFee), + value: loanValue.add(flashFee), }); await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { token: this.token.address, account: this.receiver.address, - value: receiverInitialBalance.add(loanAmount), + value: receiverInitialBalance.add(loanValue), }); await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { token: this.token.address, - value: initialSupply.add(receiverInitialBalance).add(loanAmount), + value: initialSupply.add(receiverInitialBalance).add(loanValue), }); expect(await this.token.totalSupply()).to.be.bignumber.equal( @@ -172,16 +172,16 @@ contract('ERC20FlashMint', function (accounts) { expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal('0'); - const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanAmount, '0x'); + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanValue, '0x'); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: ZERO_ADDRESS, to: this.receiver.address, - value: loanAmount, + value: loanValue, }); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.receiver.address, to: ZERO_ADDRESS, - value: loanAmount, + value: loanValue, }); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.receiver.address, @@ -191,11 +191,11 @@ contract('ERC20FlashMint', function (accounts) { await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { token: this.token.address, account: this.receiver.address, - value: receiverInitialBalance.add(loanAmount), + value: receiverInitialBalance.add(loanValue), }); await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { token: this.token.address, - value: initialSupply.add(receiverInitialBalance).add(loanAmount), + value: initialSupply.add(receiverInitialBalance).add(loanValue), }); expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply.add(receiverInitialBalance)); diff --git a/test/token/ERC20/extensions/ERC20Pausable.test.js b/test/token/ERC20/extensions/ERC20Pausable.test.js index 72bfc7769..92c90b9b8 100644 --- a/test/token/ERC20/extensions/ERC20Pausable.test.js +++ b/test/token/ERC20/extensions/ERC20Pausable.test.js @@ -84,52 +84,52 @@ contract('ERC20Pausable', function (accounts) { }); describe('mint', function () { - const amount = new BN('42'); + const value = new BN('42'); it('allows to mint when unpaused', async function () { - await this.token.$_mint(recipient, amount); + await this.token.$_mint(recipient, value); - expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); }); it('allows to mint when paused and then unpaused', async function () { await this.token.$_pause(); await this.token.$_unpause(); - await this.token.$_mint(recipient, amount); + await this.token.$_mint(recipient, value); - expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); }); it('reverts when trying to mint when paused', async function () { await this.token.$_pause(); - await expectRevertCustomError(this.token.$_mint(recipient, amount), 'EnforcedPause', []); + await expectRevertCustomError(this.token.$_mint(recipient, value), 'EnforcedPause', []); }); }); describe('burn', function () { - const amount = new BN('42'); + const value = new BN('42'); it('allows to burn when unpaused', async function () { - await this.token.$_burn(holder, amount); + await this.token.$_burn(holder, value); - expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(amount)); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(value)); }); it('allows to burn when paused and then unpaused', async function () { await this.token.$_pause(); await this.token.$_unpause(); - await this.token.$_burn(holder, amount); + await this.token.$_burn(holder, value); - expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(amount)); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(value)); }); it('reverts when trying to burn when paused', async function () { await this.token.$_pause(); - await expectRevertCustomError(this.token.$_burn(holder, amount), 'EnforcedPause', []); + await expectRevertCustomError(this.token.$_burn(holder, value), 'EnforcedPause', []); }); }); }); diff --git a/test/token/ERC20/extensions/ERC20Votes.test.js b/test/token/ERC20/extensions/ERC20Votes.test.js index 714a98adc..a6abb5f9f 100644 --- a/test/token/ERC20/extensions/ERC20Votes.test.js +++ b/test/token/ERC20/extensions/ERC20Votes.test.js @@ -10,7 +10,7 @@ const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; const { batchInBlock } = require('../../../helpers/txpool'); -const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { getDomain, domainType } = require('../../../helpers/eip712'); const { clock, clockFromReceipt } = require('../../../helpers/time'); const { expectRevertCustomError } = require('../../../helpers/customError'); @@ -48,10 +48,10 @@ contract('ERC20Votes', function (accounts) { }); it('minting restriction', async function () { - const amount = new BN('2').pow(new BN('224')); - await expectRevertCustomError(this.token.$_mint(holder, amount), 'ERC20ExceededSafeSupply', [ - amount, - amount.subn(1), + const value = web3.utils.toBN(1).shln(224); + await expectRevertCustomError(this.token.$_mint(holder, value), 'ERC20ExceededSafeSupply', [ + value, + value.subn(1), ]); }); @@ -84,8 +84,8 @@ contract('ERC20Votes', function (accounts) { }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, - previousBalance: '0', - newBalance: supply, + previousVotes: '0', + newVotes: supply, }); expect(await this.token.delegates(holder)).to.be.equal(holder); @@ -147,8 +147,8 @@ contract('ERC20Votes', function (accounts) { }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: delegatorAddress, - previousBalance: '0', - newBalance: supply, + previousVotes: '0', + newVotes: supply, }); expect(await this.token.delegates(delegatorAddress)).to.be.equal(delegatorAddress); @@ -248,13 +248,13 @@ contract('ERC20Votes', function (accounts) { }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, - previousBalance: supply, - newBalance: '0', + previousVotes: supply, + newVotes: '0', }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: holderDelegatee, - previousBalance: '0', - newBalance: supply, + previousVotes: '0', + newVotes: supply, }); expect(await this.token.delegates(holder)).to.be.equal(holderDelegatee); @@ -290,8 +290,8 @@ contract('ERC20Votes', function (accounts) { expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, - previousBalance: supply, - newBalance: supply.subn(1), + previousVotes: supply, + newVotes: supply.subn(1), }); const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); @@ -310,7 +310,7 @@ contract('ERC20Votes', function (accounts) { const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousVotes: '0', newVotes: '1' }); const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); expect( @@ -331,10 +331,10 @@ contract('ERC20Votes', function (accounts) { expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, - previousBalance: supply, - newBalance: supply.subn(1), + previousVotes: supply, + newVotes: supply.subn(1), }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousVotes: '0', newVotes: '1' }); const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); expect( diff --git a/test/token/ERC20/extensions/ERC20Wrapper.test.js b/test/token/ERC20/extensions/ERC20Wrapper.test.js index 94415d088..c54a9e007 100644 --- a/test/token/ERC20/extensions/ERC20Wrapper.test.js +++ b/test/token/ERC20/extensions/ERC20Wrapper.test.js @@ -97,6 +97,15 @@ contract('ERC20Wrapper', function (accounts) { value: initialSupply, }); }); + + it('reverts minting to the wrapper contract', async function () { + await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder }); + await expectRevertCustomError( + this.token.depositFor(this.token.address, MAX_UINT256, { from: initialHolder }), + 'ERC20InvalidReceiver', + [this.token.address], + ); + }); }); describe('withdraw', function () { @@ -156,6 +165,14 @@ contract('ERC20Wrapper', function (accounts) { value: initialSupply, }); }); + + it('reverts withdrawing to the wrapper contract', async function () { + expectRevertCustomError( + this.token.withdrawTo(this.token.address, initialSupply, { from: initialHolder }), + 'ERC20InvalidReceiver', + [this.token.address], + ); + }); }); describe('recover', function () { diff --git a/test/token/ERC20/extensions/ERC4626.test.js b/test/token/ERC20/extensions/ERC4626.test.js index 99d6009e4..9dfc4c3b8 100644 --- a/test/token/ERC20/extensions/ERC4626.test.js +++ b/test/token/ERC20/extensions/ERC4626.test.js @@ -52,8 +52,8 @@ contract('ERC4626', function (accounts) { describe('reentrancy', async function () { const reenterType = Enum('No', 'Before', 'After'); - const amount = web3.utils.toBN(1000000000000000000); - const reenterAmount = web3.utils.toBN(1000000000); + const value = web3.utils.toBN(1000000000000000000); + const reenterValue = web3.utils.toBN(1000000000); let token; let vault; @@ -62,8 +62,8 @@ contract('ERC4626', function (accounts) { // Use offset 1 so the rate is not 1:1 and we can't possibly confuse assets and shares vault = await ERC4626OffsetMock.new('', '', token.address, 1); // Funds and approval for tests - await token.$_mint(holder, amount); - await token.$_mint(other, amount); + await token.$_mint(holder, value); + await token.$_mint(other, value); await token.$_approve(holder, vault.address, constants.MAX_UINT256); await token.$_approve(other, vault.address, constants.MAX_UINT256); await token.$_approve(token.address, vault.address, constants.MAX_UINT256); @@ -75,39 +75,39 @@ contract('ERC4626', function (accounts) { // intermediate state in which the ratio of assets/shares has been decreased (more shares than assets). it('correct share price is observed during reentrancy before deposit', async function () { // mint token for deposit - await token.$_mint(token.address, reenterAmount); + await token.$_mint(token.address, reenterValue); // Schedules a reentrancy from the token contract await token.scheduleReenter( reenterType.Before, vault.address, - vault.contract.methods.deposit(reenterAmount, holder).encodeABI(), + vault.contract.methods.deposit(reenterValue, holder).encodeABI(), ); // Initial share price - const sharesForDeposit = await vault.previewDeposit(amount, { from: holder }); - const sharesForReenter = await vault.previewDeposit(reenterAmount, { from: holder }); + const sharesForDeposit = await vault.previewDeposit(value, { from: holder }); + const sharesForReenter = await vault.previewDeposit(reenterValue, { from: holder }); // Do deposit normally, triggering the _beforeTokenTransfer hook - const receipt = await vault.deposit(amount, holder, { from: holder }); + const receipt = await vault.deposit(value, holder, { from: holder }); // Main deposit event await expectEvent(receipt, 'Deposit', { sender: holder, owner: holder, - assets: amount, + assets: value, shares: sharesForDeposit, }); // Reentrant deposit event → uses the same price await expectEvent(receipt, 'Deposit', { sender: token.address, owner: holder, - assets: reenterAmount, + assets: reenterValue, shares: sharesForReenter, }); // Assert prices is kept - const sharesAfter = await vault.previewDeposit(amount, { from: holder }); + const sharesAfter = await vault.previewDeposit(value, { from: holder }); expect(sharesForDeposit).to.be.bignumber.eq(sharesAfter); }); @@ -116,30 +116,30 @@ contract('ERC4626', function (accounts) { // If the order of burn -> transfer is changed to transfer -> burn, the reentrancy could be triggered on an // intermediate state in which the ratio of shares/assets has been decreased (more assets than shares). it('correct share price is observed during reentrancy after withdraw', async function () { - // Deposit into the vault: holder gets `amount` share, token.address gets `reenterAmount` shares - await vault.deposit(amount, holder, { from: holder }); - await vault.deposit(reenterAmount, token.address, { from: other }); + // Deposit into the vault: holder gets `value` share, token.address gets `reenterValue` shares + await vault.deposit(value, holder, { from: holder }); + await vault.deposit(reenterValue, token.address, { from: other }); // Schedules a reentrancy from the token contract await token.scheduleReenter( reenterType.After, vault.address, - vault.contract.methods.withdraw(reenterAmount, holder, token.address).encodeABI(), + vault.contract.methods.withdraw(reenterValue, holder, token.address).encodeABI(), ); // Initial share price - const sharesForWithdraw = await vault.previewWithdraw(amount, { from: holder }); - const sharesForReenter = await vault.previewWithdraw(reenterAmount, { from: holder }); + const sharesForWithdraw = await vault.previewWithdraw(value, { from: holder }); + const sharesForReenter = await vault.previewWithdraw(reenterValue, { from: holder }); // Do withdraw normally, triggering the _afterTokenTransfer hook - const receipt = await vault.withdraw(amount, holder, holder, { from: holder }); + const receipt = await vault.withdraw(value, holder, holder, { from: holder }); // Main withdraw event await expectEvent(receipt, 'Withdraw', { sender: holder, receiver: holder, owner: holder, - assets: amount, + assets: value, shares: sharesForWithdraw, }); // Reentrant withdraw event → uses the same price @@ -147,76 +147,76 @@ contract('ERC4626', function (accounts) { sender: token.address, receiver: holder, owner: token.address, - assets: reenterAmount, + assets: reenterValue, shares: sharesForReenter, }); // Assert price is kept - const sharesAfter = await vault.previewWithdraw(amount, { from: holder }); + const sharesAfter = await vault.previewWithdraw(value, { from: holder }); expect(sharesForWithdraw).to.be.bignumber.eq(sharesAfter); }); // Donate newly minted tokens to the vault during the reentracy causes the share price to increase. // Still, the deposit that trigger the reentracy is not affected and get the previewed price. - // Further deposits will get a different price (getting fewer shares for the same amount of assets) + // Further deposits will get a different price (getting fewer shares for the same value of assets) it('share price change during reentracy does not affect deposit', async function () { // Schedules a reentrancy from the token contract that mess up the share price await token.scheduleReenter( reenterType.Before, token.address, - token.contract.methods.$_mint(vault.address, reenterAmount).encodeABI(), + token.contract.methods.$_mint(vault.address, reenterValue).encodeABI(), ); // Price before - const sharesBefore = await vault.previewDeposit(amount); + const sharesBefore = await vault.previewDeposit(value); // Deposit, triggering the _beforeTokenTransfer hook - const receipt = await vault.deposit(amount, holder, { from: holder }); + const receipt = await vault.deposit(value, holder, { from: holder }); // Price is as previewed await expectEvent(receipt, 'Deposit', { sender: holder, owner: holder, - assets: amount, + assets: value, shares: sharesBefore, }); // Price was modified during reentrancy - const sharesAfter = await vault.previewDeposit(amount); + const sharesAfter = await vault.previewDeposit(value); expect(sharesAfter).to.be.bignumber.lt(sharesBefore); }); // Burn some tokens from the vault during the reentracy causes the share price to drop. // Still, the withdraw that trigger the reentracy is not affected and get the previewed price. - // Further withdraw will get a different price (needing more shares for the same amount of assets) + // Further withdraw will get a different price (needing more shares for the same value of assets) it('share price change during reentracy does not affect withdraw', async function () { - await vault.deposit(amount, other, { from: other }); - await vault.deposit(amount, holder, { from: holder }); + await vault.deposit(value, other, { from: other }); + await vault.deposit(value, holder, { from: holder }); // Schedules a reentrancy from the token contract that mess up the share price await token.scheduleReenter( reenterType.After, token.address, - token.contract.methods.$_burn(vault.address, reenterAmount).encodeABI(), + token.contract.methods.$_burn(vault.address, reenterValue).encodeABI(), ); // Price before - const sharesBefore = await vault.previewWithdraw(amount); + const sharesBefore = await vault.previewWithdraw(value); // Withdraw, triggering the _afterTokenTransfer hook - const receipt = await vault.withdraw(amount, holder, holder, { from: holder }); + const receipt = await vault.withdraw(value, holder, holder, { from: holder }); // Price is as previewed await expectEvent(receipt, 'Withdraw', { sender: holder, receiver: holder, owner: holder, - assets: amount, + assets: value, shares: sharesBefore, }); // Price was modified during reentrancy - const sharesAfter = await vault.previewWithdraw(amount); + const sharesAfter = await vault.previewWithdraw(value); expect(sharesAfter).to.be.bignumber.gt(sharesBefore); }); }); @@ -738,9 +738,9 @@ contract('ERC4626', function (accounts) { describe('ERC4626Fees', function () { const feeBasePoint = web3.utils.toBN(5e3); - const amountWithoutFees = web3.utils.toBN(10000); - const fees = amountWithoutFees.mul(feeBasePoint).divn(1e5); - const amountWithFees = amountWithoutFees.add(fees); + const valueWithoutFees = web3.utils.toBN(10000); + const fees = valueWithoutFees.mul(feeBasePoint).divn(1e5); + const valueWithFees = valueWithoutFees.add(fees); describe('input fees', function () { beforeEach(async function () { @@ -760,13 +760,13 @@ contract('ERC4626', function (accounts) { }); it('deposit', async function () { - expect(await this.vault.previewDeposit(amountWithFees)).to.be.bignumber.equal(amountWithoutFees); - ({ tx: this.tx } = await this.vault.deposit(amountWithFees, recipient, { from: holder })); + expect(await this.vault.previewDeposit(valueWithFees)).to.be.bignumber.equal(valueWithoutFees); + ({ tx: this.tx } = await this.vault.deposit(valueWithFees, recipient, { from: holder })); }); it('mint', async function () { - expect(await this.vault.previewMint(amountWithoutFees)).to.be.bignumber.equal(amountWithFees); - ({ tx: this.tx } = await this.vault.mint(amountWithoutFees, recipient, { from: holder })); + expect(await this.vault.previewMint(valueWithoutFees)).to.be.bignumber.equal(valueWithFees); + ({ tx: this.tx } = await this.vault.mint(valueWithoutFees, recipient, { from: holder })); }); afterEach(async function () { @@ -774,7 +774,7 @@ contract('ERC4626', function (accounts) { await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { from: holder, to: this.vault.address, - value: amountWithFees, + value: valueWithFees, }); // redirect fees @@ -788,15 +788,15 @@ contract('ERC4626', function (accounts) { await expectEvent.inTransaction(this.tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, - value: amountWithoutFees, + value: valueWithoutFees, }); // deposit event await expectEvent.inTransaction(this.tx, this.vault, 'Deposit', { sender: holder, owner: recipient, - assets: amountWithFees, - shares: amountWithoutFees, + assets: valueWithFees, + shares: valueWithoutFees, }); }); }); @@ -819,13 +819,13 @@ contract('ERC4626', function (accounts) { }); it('redeem', async function () { - expect(await this.vault.previewRedeem(amountWithFees)).to.be.bignumber.equal(amountWithoutFees); - ({ tx: this.tx } = await this.vault.redeem(amountWithFees, recipient, holder, { from: holder })); + expect(await this.vault.previewRedeem(valueWithFees)).to.be.bignumber.equal(valueWithoutFees); + ({ tx: this.tx } = await this.vault.redeem(valueWithFees, recipient, holder, { from: holder })); }); it('withdraw', async function () { - expect(await this.vault.previewWithdraw(amountWithoutFees)).to.be.bignumber.equal(amountWithFees); - ({ tx: this.tx } = await this.vault.withdraw(amountWithoutFees, recipient, holder, { from: holder })); + expect(await this.vault.previewWithdraw(valueWithoutFees)).to.be.bignumber.equal(valueWithFees); + ({ tx: this.tx } = await this.vault.withdraw(valueWithoutFees, recipient, holder, { from: holder })); }); afterEach(async function () { @@ -833,7 +833,7 @@ contract('ERC4626', function (accounts) { await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, - value: amountWithoutFees, + value: valueWithoutFees, }); // redirect fees @@ -847,7 +847,7 @@ contract('ERC4626', function (accounts) { await expectEvent.inTransaction(this.tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, - value: amountWithFees, + value: valueWithFees, }); // withdraw event @@ -855,8 +855,8 @@ contract('ERC4626', function (accounts) { sender: holder, receiver: recipient, owner: holder, - assets: amountWithoutFees, - shares: amountWithFees, + assets: valueWithoutFees, + shares: valueWithFees, }); }); }); diff --git a/test/token/ERC721/extensions/ERC721Votes.test.js b/test/token/ERC721/extensions/ERC721Votes.test.js index caa44ea8b..45020baf9 100644 --- a/test/token/ERC721/extensions/ERC721Votes.test.js +++ b/test/token/ERC721/extensions/ERC721Votes.test.js @@ -61,7 +61,7 @@ contract('ERC721Votes', function (accounts) { const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousVotes: '1', newVotes: '0' }); const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); expect( @@ -79,7 +79,7 @@ contract('ERC721Votes', function (accounts) { const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousBalance: '0', newBalance: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousVotes: '0', newVotes: '1' }); const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); expect( @@ -98,8 +98,8 @@ contract('ERC721Votes', function (accounts) { const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0' }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousBalance: '0', newBalance: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousVotes: '1', newVotes: '0' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousVotes: '0', newVotes: '1' }); const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); expect( From 6e214227376acd688e60fcdca8cb7f0ae8cef98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Mon, 3 Jul 2023 14:29:30 -0600 Subject: [PATCH 09/16] Add Governor signature nonces (#4378) Co-authored-by: Hadrien Croubois Co-authored-by: Francisco Co-authored-by: Sergei Tikhomirov Co-authored-by: Renan Souza --- .changeset/sixty-numbers-reply.md | 5 + contracts/governance/Governor.sol | 33 +++-- contracts/governance/IGovernor.sol | 7 + hardhat.config.js | 1 + package-lock.json | 12 +- test/governance/Governor.test.js | 101 +++++++++++++- .../extensions/GovernorWithParams.test.js | 124 +++++++++++++----- test/helpers/governance.js | 46 ++++--- .../SupportsInterface.behavior.js | 6 +- 9 files changed, 263 insertions(+), 72 deletions(-) create mode 100644 .changeset/sixty-numbers-reply.md diff --git a/.changeset/sixty-numbers-reply.md b/.changeset/sixty-numbers-reply.md new file mode 100644 index 000000000..4e6faa837 --- /dev/null +++ b/.changeset/sixty-numbers-reply.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': major +--- + +`Governor`: Add `voter` and `nonce` parameters in signed ballots, to avoid forging signatures for random addresses, prevent signature replay, and allow invalidating signatures. Add `voter` as a new parameter in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index d0ace4f03..1e1526ceb 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -12,6 +12,7 @@ import {SafeCast} from "../utils/math/SafeCast.sol"; import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; import {Address} from "../utils/Address.sol"; import {Context} from "../utils/Context.sol"; +import {Nonces} from "../utils/Nonces.sol"; import {IGovernor, IERC6372} from "./IGovernor.sol"; /** @@ -25,12 +26,15 @@ import {IGovernor, IERC6372} from "./IGovernor.sol"; * * _Available since v4.3._ */ -abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receiver, IERC1155Receiver { +abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC721Receiver, IERC1155Receiver { using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; - bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,uint8 support)"); + bytes32 public constant BALLOT_TYPEHASH = + keccak256("Ballot(uint256 proposalId,uint8 support,address voter,uint256 nonce)"); bytes32 public constant EXTENDED_BALLOT_TYPEHASH = - keccak256("ExtendedBallot(uint256 proposalId,uint8 support,string reason,bytes params)"); + keccak256( + "ExtendedBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason,bytes params)" + ); // solhint-disable var-name-mixedcase struct ProposalCore { @@ -514,17 +518,23 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive function castVoteBySig( uint256 proposalId, uint8 support, + address voter, uint8 v, bytes32 r, bytes32 s ) public virtual override returns (uint256) { - address voter = ECDSA.recover( - _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support))), + address signer = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter)))), v, r, s ); - return _castVote(proposalId, voter, support, ""); + + if (voter != signer) { + revert GovernorInvalidSigner(signer, voter); + } + + return _castVote(proposalId, signer, support, ""); } /** @@ -533,19 +543,22 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive function castVoteWithReasonAndParamsBySig( uint256 proposalId, uint8 support, + address voter, string calldata reason, bytes memory params, uint8 v, bytes32 r, bytes32 s ) public virtual override returns (uint256) { - address voter = ECDSA.recover( + address signer = ECDSA.recover( _hashTypedDataV4( keccak256( abi.encode( EXTENDED_BALLOT_TYPEHASH, proposalId, support, + voter, + _useNonce(voter), keccak256(bytes(reason)), keccak256(params) ) @@ -556,7 +569,11 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive s ); - return _castVote(proposalId, voter, support, reason, params); + if (voter != signer) { + revert GovernorInvalidSigner(signer, voter); + } + + return _castVote(proposalId, signer, support, reason, params); } /** diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index 2eeedd313..20636e3ba 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -80,6 +80,11 @@ abstract contract IGovernor is IERC165, IERC6372 { */ error GovernorInvalidVoteType(); + /** + * @dev The `voter` doesn't match with the recovered `signer`. + */ + error GovernorInvalidSigner(address signer, address voter); + /** * @dev Emitted when a proposal is created. */ @@ -355,6 +360,7 @@ abstract contract IGovernor is IERC165, IERC6372 { function castVoteBySig( uint256 proposalId, uint8 support, + address voter, uint8 v, bytes32 r, bytes32 s @@ -368,6 +374,7 @@ abstract contract IGovernor is IERC165, IERC6372 { function castVoteWithReasonAndParamsBySig( uint256 proposalId, uint8 support, + address voter, string calldata reason, bytes memory params, uint8 v, diff --git a/hardhat.config.js b/hardhat.config.js index 6cb8b9144..8ee5d05e5 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -78,6 +78,7 @@ module.exports = { warnings: { 'contracts-exposed/**/*': { 'code-size': 'off', + 'initcode-size': 'off', }, '*': { 'code-size': withOptimizations, diff --git a/package-lock.json b/package-lock.json index a85611941..2e6296d24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7504,9 +7504,9 @@ } }, "node_modules/hardhat-ignore-warnings": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.8.tgz", - "integrity": "sha512-vPX94rJyTzYsCOzGIYdOcJgn3iQI6qa+CI9ZZfgDhdXJpda8ljpOT7bdUKAYC4LyoP0Z5fWTmupXoPaQrty0gw==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.9.tgz", + "integrity": "sha512-q1oj6/ixiAx+lgIyGLBajVCSC7qUtAoK7LS9Nr8UVHYo8Iuh5naBiVGo4RDJ6wxbDGYBkeSukUGZrMqzC2DWwA==", "dev": true, "dependencies": { "minimatch": "^5.1.0", @@ -21441,9 +21441,9 @@ } }, "hardhat-ignore-warnings": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.8.tgz", - "integrity": "sha512-vPX94rJyTzYsCOzGIYdOcJgn3iQI6qa+CI9ZZfgDhdXJpda8ljpOT7bdUKAYC4LyoP0Z5fWTmupXoPaQrty0gw==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.9.tgz", + "integrity": "sha512-q1oj6/ixiAx+lgIyGLBajVCSC7qUtAoK7LS9Nr8UVHYo8Iuh5naBiVGo4RDJ6wxbDGYBkeSukUGZrMqzC2DWwA==", "dev": true, "requires": { "minimatch": "^5.1.0", diff --git a/test/governance/Governor.test.js b/test/governance/Governor.test.js index 909c38686..f4a352c6d 100644 --- a/test/governance/Governor.test.js +++ b/test/governance/Governor.test.js @@ -2,7 +2,7 @@ const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-hel const { expect } = require('chai'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { fromRpcSig } = require('ethereumjs-util'); +const { fromRpcSig, toRpcSig } = require('ethereumjs-util'); const Enums = require('../helpers/enums'); const { getDomain, domainType } = require('../helpers/eip712'); @@ -166,7 +166,7 @@ contract('Governor', function (accounts) { expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value); }); - it('vote with signature', async function () { + it('votes with signature', async function () { const voterBySig = Wallet.generate(); const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); @@ -179,6 +179,8 @@ contract('Governor', function (accounts) { Ballot: [ { name: 'proposalId', type: 'uint256' }, { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, ], }, domain, @@ -189,13 +191,19 @@ contract('Governor', function (accounts) { await this.token.delegate(voterBySigAddress, { from: voter1 }); + const nonce = await this.mock.nonces(voterBySigAddress); + // Run proposal await this.helper.propose(); await this.helper.waitForSnapshot(); - expectEvent(await this.helper.vote({ support: Enums.VoteType.For, signature }), 'VoteCast', { - voter: voterBySigAddress, - support: Enums.VoteType.For, - }); + expectEvent( + await this.helper.vote({ support: Enums.VoteType.For, voter: voterBySigAddress, nonce, signature }), + 'VoteCast', + { + voter: voterBySigAddress, + support: Enums.VoteType.For, + }, + ); await this.helper.waitForDeadline(); await this.helper.execute(); @@ -204,6 +212,7 @@ contract('Governor', function (accounts) { expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); expect(await this.mock.hasVoted(this.proposal.id, voterBySigAddress)).to.be.equal(true); + expect(await this.mock.nonces(voterBySigAddress)).to.be.bignumber.equal(nonce.addn(1)); }); it('send ethers', async function () { @@ -297,6 +306,86 @@ contract('Governor', function (accounts) { }); }); + describe('on vote by signature', function () { + beforeEach(async function () { + this.voterBySig = Wallet.generate(); + this.voterBySig.address = web3.utils.toChecksumAddress(this.voterBySig.getAddressString()); + + this.data = (contract, message) => + getDomain(contract).then(domain => ({ + primaryType: 'Ballot', + types: { + EIP712Domain: domainType(domain), + Ballot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + ], + }, + domain, + message, + })); + + this.signature = (contract, message) => + this.data(contract, message) + .then(data => ethSigUtil.signTypedMessage(this.voterBySig.getPrivateKey(), { data })) + .then(fromRpcSig); + + await this.token.delegate(this.voterBySig.address, { from: voter1 }); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + }); + + it('if signature does not match signer', async function () { + const nonce = await this.mock.nonces(this.voterBySig.address); + + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + signature: async (...params) => { + const sig = await this.signature(...params); + sig.s[12] ^= 0xff; + return sig; + }, + }; + + const { r, s, v } = await this.helper.sign(voteParams); + const message = this.helper.forgeMessage(voteParams); + const data = await this.data(this.mock, message); + + await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSigner', [ + ethSigUtil.recoverTypedSignature({ sig: toRpcSig(v, r, s), data }), + voteParams.voter, + ]); + }); + + it('if vote nonce is incorrect', async function () { + const nonce = await this.mock.nonces(this.voterBySig.address); + + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce: nonce.addn(1), + signature: this.signature, + }; + + const { r, s, v } = await this.helper.sign(voteParams); + const message = this.helper.forgeMessage(voteParams); + const data = await this.data(this.mock, { ...message, nonce }); + + await expectRevertCustomError( + this.helper.vote(voteParams), + // The signature check implies the nonce can't be tampered without changing the signer + 'GovernorInvalidSigner', + [ethSigUtil.recoverTypedSignature({ sig: toRpcSig(v, r, s), data }), voteParams.voter], + ); + }); + }); + describe('on execute', function () { it('if proposal does not exist', async function () { await expectRevertCustomError(this.helper.execute(), 'GovernorNonexistentProposal', [this.proposal.id]); diff --git a/test/governance/extensions/GovernorWithParams.test.js b/test/governance/extensions/GovernorWithParams.test.js index 00936c505..fb58edaaf 100644 --- a/test/governance/extensions/GovernorWithParams.test.js +++ b/test/governance/extensions/GovernorWithParams.test.js @@ -2,11 +2,12 @@ const { expectEvent } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { fromRpcSig } = require('ethereumjs-util'); +const { fromRpcSig, toRpcSig } = require('ethereumjs-util'); const Enums = require('../../helpers/enums'); const { getDomain, domainType } = require('../../helpers/eip712'); const { GovernorHelper } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); const Governor = artifacts.require('$GovernorWithParamsMock'); const CallReceiver = artifacts.require('CallReceiverMock'); @@ -119,56 +120,119 @@ contract('GovernorWithParams', function (accounts) { expect(votes.forVotes).to.be.bignumber.equal(weight); }); - it('Voting with params by signature is properly supported', async function () { - const voterBySig = Wallet.generate(); - const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); + describe('voting by signature', function () { + beforeEach(async function () { + this.voterBySig = Wallet.generate(); + this.voterBySig.address = web3.utils.toChecksumAddress(this.voterBySig.getAddressString()); - const signature = (contract, message) => - getDomain(contract) - .then(domain => ({ + this.data = (contract, message) => + getDomain(contract).then(domain => ({ primaryType: 'ExtendedBallot', types: { EIP712Domain: domainType(domain), ExtendedBallot: [ { name: 'proposalId', type: 'uint256' }, { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, { name: 'reason', type: 'string' }, { name: 'params', type: 'bytes' }, ], }, domain, message, - })) - .then(data => ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { data })) - .then(fromRpcSig); + })); - await this.token.delegate(voterBySigAddress, { from: voter2 }); + this.signature = (contract, message) => + this.data(contract, message) + .then(data => ethSigUtil.signTypedMessage(this.voterBySig.getPrivateKey(), { data })) + .then(fromRpcSig); - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); + await this.token.delegate(this.voterBySig.address, { from: voter2 }); - const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + }); - const tx = await this.helper.vote({ - support: Enums.VoteType.For, - reason: 'no particular reason', - params: encodedParams, - signature, + it('is properly supported', async function () { + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); + + const nonce = await this.mock.nonces(this.voterBySig.address); + + const tx = await this.helper.vote({ + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + reason: 'no particular reason', + params: encodedParams, + signature: this.signature, + }); + + expectEvent(tx, 'CountParams', { ...rawParams }); + expectEvent(tx, 'VoteCastWithParams', { + voter: this.voterBySig.address, + proposalId: this.proposal.id, + support: Enums.VoteType.For, + weight, + reason: 'no particular reason', + params: encodedParams, + }); + + const votes = await this.mock.proposalVotes(this.proposal.id); + expect(votes.forVotes).to.be.bignumber.equal(weight); + expect(await this.mock.nonces(this.voterBySig.address)).to.be.bignumber.equal(nonce.addn(1)); }); - expectEvent(tx, 'CountParams', { ...rawParams }); - expectEvent(tx, 'VoteCastWithParams', { - voter: voterBySigAddress, - proposalId: this.proposal.id, - support: Enums.VoteType.For, - weight, - reason: 'no particular reason', - params: encodedParams, + it('reverts if signature does not match signer', async function () { + const nonce = await this.mock.nonces(this.voterBySig.address); + + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + signature: async (...params) => { + const sig = await this.signature(...params); + sig.s[12] ^= 0xff; + return sig; + }, + reason: 'no particular reason', + params: encodedParams, + }; + + const { r, s, v } = await this.helper.sign(voteParams); + const message = this.helper.forgeMessage(voteParams); + const data = await this.data(this.mock, message); + + await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSigner', [ + ethSigUtil.recoverTypedSignature({ sig: toRpcSig(v, r, s), data }), + voteParams.voter, + ]); }); - const votes = await this.mock.proposalVotes(this.proposal.id); - expect(votes.forVotes).to.be.bignumber.equal(weight); + it('reverts if vote nonce is incorrect', async function () { + const nonce = await this.mock.nonces(this.voterBySig.address); + + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce: nonce.addn(1), + signature: this.signature, + reason: 'no particular reason', + params: encodedParams, + }; + + const { r, s, v } = await this.helper.sign(voteParams); + const message = this.helper.forgeMessage(voteParams); + const data = await this.data(this.mock, { ...message, nonce }); + + await expectRevertCustomError( + this.helper.vote(voteParams), + // The signature check implies the nonce can't be tampered without changing the signer + 'GovernorInvalidSigner', + [ethSigUtil.recoverTypedSignature({ sig: toRpcSig(v, r, s), data }), voteParams.voter], + ); + }); }); }); } diff --git a/test/helpers/governance.js b/test/helpers/governance.js index 665c21605..588aeb258 100644 --- a/test/helpers/governance.js +++ b/test/helpers/governance.js @@ -91,26 +91,17 @@ class GovernorHelper { return vote.signature ? // if signature, and either params or reason → vote.params || vote.reason - ? vote - .signature(this.governor, { - proposalId: proposal.id, - support: vote.support, - reason: vote.reason || '', - params: vote.params || '', - }) - .then(({ v, r, s }) => - this.governor.castVoteWithReasonAndParamsBySig( - ...concatOpts([proposal.id, vote.support, vote.reason || '', vote.params || '', v, r, s], opts), + ? this.sign(vote).then(({ v, r, s }) => + this.governor.castVoteWithReasonAndParamsBySig( + ...concatOpts( + [proposal.id, vote.support, vote.voter, vote.reason || '', vote.params || '', v, r, s], + opts, ), - ) - : vote - .signature(this.governor, { - proposalId: proposal.id, - support: vote.support, - }) - .then(({ v, r, s }) => - this.governor.castVoteBySig(...concatOpts([proposal.id, vote.support, v, r, s], opts)), - ) + ), + ) + : this.sign(vote).then(({ v, r, s }) => + this.governor.castVoteBySig(...concatOpts([proposal.id, vote.support, vote.voter, v, r, s], opts)), + ) : vote.params ? // otherwise if params this.governor.castVoteWithReasonAndParams( @@ -122,6 +113,23 @@ class GovernorHelper { : this.governor.castVote(...concatOpts([proposal.id, vote.support], opts)); } + sign(vote = {}) { + return vote.signature(this.governor, this.forgeMessage(vote)); + } + + forgeMessage(vote = {}) { + const proposal = this.currentProposal; + + const message = { proposalId: proposal.id, support: vote.support, voter: vote.voter, nonce: vote.nonce }; + + if (vote.params || vote.reason) { + message.reason = vote.reason || ''; + message.params = vote.params || ''; + } + + return message; + } + async waitForSnapshot(offset = 0) { const proposal = this.currentProposal; const timepoint = await this.governor.proposalSnapshot(proposal.id); diff --git a/test/utils/introspection/SupportsInterface.behavior.js b/test/utils/introspection/SupportsInterface.behavior.js index 201a55f47..71be4313f 100644 --- a/test/utils/introspection/SupportsInterface.behavior.js +++ b/test/utils/introspection/SupportsInterface.behavior.js @@ -66,7 +66,7 @@ const INTERFACES = { 'execute(address[],uint256[],bytes[],bytes32)', 'castVote(uint256,uint8)', 'castVoteWithReason(uint256,uint8,string)', - 'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)', + 'castVoteBySig(uint256,uint8,address,uint8,bytes32,bytes32)', ], GovernorWithParams: [ 'name()', @@ -87,8 +87,8 @@ const INTERFACES = { 'castVote(uint256,uint8)', 'castVoteWithReason(uint256,uint8,string)', 'castVoteWithReasonAndParams(uint256,uint8,string,bytes)', - 'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)', - 'castVoteWithReasonAndParamsBySig(uint256,uint8,string,bytes,uint8,bytes32,bytes32)', + 'castVoteBySig(uint256,uint8,address,uint8,bytes32,bytes32)', + 'castVoteWithReasonAndParamsBySig(uint256,uint8,address,string,bytes,uint8,bytes32,bytes32)', ], GovernorCancel: ['proposalProposer(uint256)', 'cancel(address[],uint256[],bytes[],bytes32)'], GovernorTimelock: ['timelock()', 'proposalEta(uint256)', 'queue(address[],uint256[],bytes[],bytes32)'], From e3adf91e505d3125a1ce9a05aae76b36ed800170 Mon Sep 17 00:00:00 2001 From: Renan Souza Date: Tue, 4 Jul 2023 15:23:44 -0300 Subject: [PATCH 10/16] Add state getter in TimelockController using OperationState enum (#4358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Francisco Co-authored-by: Ernesto García --- .changeset/loud-shrimps-play.md | 5 ++ contracts/governance/README.adoc | 5 +- contracts/governance/TimelockController.sol | 68 +++++++++++++++---- test/governance/TimelockController.test.js | 23 ++++--- .../GovernorTimelockControl.test.js | 4 +- test/helpers/enums.js | 2 +- 6 files changed, 75 insertions(+), 32 deletions(-) create mode 100644 .changeset/loud-shrimps-play.md diff --git a/.changeset/loud-shrimps-play.md b/.changeset/loud-shrimps-play.md new file mode 100644 index 000000000..3de2da080 --- /dev/null +++ b/.changeset/loud-shrimps-play.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`TimelockController`: Add a state getter that returns an `OperationState` enum. diff --git a/contracts/governance/README.adoc b/contracts/governance/README.adoc index 00edfe23d..29c3887c7 100644 --- a/contracts/governance/README.adoc +++ b/contracts/governance/README.adoc @@ -52,8 +52,6 @@ NOTE: Functions of the `Governor` contract do not include access control. If you === Core -{{IGovernor}} - {{Governor}} === Modules @@ -92,8 +90,9 @@ In a governance system, the {TimelockController} contract is in charge of introd * *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content. * *Operation status:* ** *Unset:* An operation that is not part of the timelock mechanism. -** *Pending:* An operation that has been scheduled, before the timer expires. +** *Waiting:* An operation that has been scheduled, before the timer expires. ** *Ready:* An operation that has been scheduled, after the timer expires. +** *Pending:* An operation that is either waiting or ready. ** *Done:* An operation that has been executed. * *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations. * *Role*: diff --git a/contracts/governance/TimelockController.sol b/contracts/governance/TimelockController.sol index 56a25fe30..ff8d45595 100644 --- a/contracts/governance/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -35,7 +35,7 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { enum OperationState { Unset, - Pending, + Waiting, Ready, Done } @@ -52,8 +52,12 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { /** * @dev The current state of an operation is not as required. + * The `expectedStates` is a bitmap with the bits enabled for each OperationState enum position + * counting from right to left. + * + * See {_encodeStateBitmap}. */ - error TimelockUnexpectedOperationState(bytes32 operationId, OperationState expected); + error TimelockUnexpectedOperationState(bytes32 operationId, bytes32 expectedStates); /** * @dev The predecessor to an operation not yet done. @@ -166,30 +170,30 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { * @dev Returns whether an id correspond to a registered operation. This * includes both Pending, Ready and Done operations. */ - function isOperation(bytes32 id) public view virtual returns (bool) { - return getTimestamp(id) > 0; + function isOperation(bytes32 id) public view returns (bool) { + return getOperationState(id) != OperationState.Unset; } /** * @dev Returns whether an operation is pending or not. Note that a "pending" operation may also be "ready". */ - function isOperationPending(bytes32 id) public view virtual returns (bool) { - return getTimestamp(id) > _DONE_TIMESTAMP; + function isOperationPending(bytes32 id) public view returns (bool) { + OperationState state = getOperationState(id); + return state == OperationState.Waiting || state == OperationState.Ready; } /** * @dev Returns whether an operation is ready for execution. Note that a "ready" operation is also "pending". */ - function isOperationReady(bytes32 id) public view virtual returns (bool) { - uint256 timestamp = getTimestamp(id); - return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp; + function isOperationReady(bytes32 id) public view returns (bool) { + return getOperationState(id) == OperationState.Ready; } /** * @dev Returns whether an operation is done or not. */ - function isOperationDone(bytes32 id) public view virtual returns (bool) { - return getTimestamp(id) == _DONE_TIMESTAMP; + function isOperationDone(bytes32 id) public view returns (bool) { + return getOperationState(id) == OperationState.Done; } /** @@ -200,6 +204,22 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { return _timestamps[id]; } + /** + * @dev Returns operation state. + */ + function getOperationState(bytes32 id) public view virtual returns (OperationState) { + uint256 timestamp = getTimestamp(id); + if (timestamp == 0) { + return OperationState.Unset; + } else if (timestamp == _DONE_TIMESTAMP) { + return OperationState.Done; + } else if (timestamp > block.timestamp) { + return OperationState.Waiting; + } else { + return OperationState.Ready; + } + } + /** * @dev Returns the minimum delay for an operation to become valid. * @@ -298,7 +318,7 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { */ function _schedule(bytes32 id, uint256 delay) private { if (isOperation(id)) { - revert TimelockUnexpectedOperationState(id, OperationState.Unset); + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Unset)); } uint256 minDelay = getMinDelay(); if (delay < minDelay) { @@ -316,7 +336,10 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { */ function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) { if (!isOperationPending(id)) { - revert TimelockUnexpectedOperationState(id, OperationState.Pending); + revert TimelockUnexpectedOperationState( + id, + _encodeStateBitmap(OperationState.Waiting) | _encodeStateBitmap(OperationState.Ready) + ); } delete _timestamps[id]; @@ -399,7 +422,7 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { */ function _beforeCall(bytes32 id, bytes32 predecessor) private view { if (!isOperationReady(id)) { - revert TimelockUnexpectedOperationState(id, OperationState.Ready); + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready)); } if (predecessor != bytes32(0) && !isOperationDone(predecessor)) { revert TimelockUnexecutedPredecessor(predecessor); @@ -411,7 +434,7 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { */ function _afterCall(bytes32 id) private { if (!isOperationReady(id)) { - revert TimelockUnexpectedOperationState(id, OperationState.Ready); + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready)); } _timestamps[id] = _DONE_TIMESTAMP; } @@ -434,4 +457,19 @@ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { emit MinDelayChange(_minDelay, newDelay); _minDelay = newDelay; } + + /** + * @dev Encodes a `OperationState` into a `bytes32` representation where each bit enabled corresponds to + * the underlying position in the `OperationState` enum. For example: + * + * 0x000...1000 + * ^^^^^^----- ... + * ^---- Done + * ^--- Ready + * ^-- Waiting + * ^- Unset + */ + function _encodeStateBitmap(OperationState operationState) internal pure returns (bytes32) { + return bytes32(1 << uint8(operationState)); + } } diff --git a/test/governance/TimelockController.test.js b/test/governance/TimelockController.test.js index d8fcdce6c..ce051e787 100644 --- a/test/governance/TimelockController.test.js +++ b/test/governance/TimelockController.test.js @@ -1,5 +1,6 @@ const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); const { ZERO_ADDRESS, ZERO_BYTES32 } = constants; +const { proposalStatesToBitMap } = require('../helpers/governance'); const { expect } = require('chai'); @@ -195,7 +196,7 @@ contract('TimelockController', function (accounts) { { from: proposer }, ), 'TimelockUnexpectedOperationState', - [this.operation.id, OperationState.Unset], + [this.operation.id, proposalStatesToBitMap(OperationState.Unset)], ); }); @@ -267,7 +268,7 @@ contract('TimelockController', function (accounts) { { from: executor }, ), 'TimelockUnexpectedOperationState', - [this.operation.id, OperationState.Ready], + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], ); }); @@ -295,7 +296,7 @@ contract('TimelockController', function (accounts) { { from: executor }, ), 'TimelockUnexpectedOperationState', - [this.operation.id, OperationState.Ready], + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], ); }); @@ -313,7 +314,7 @@ contract('TimelockController', function (accounts) { { from: executor }, ), 'TimelockUnexpectedOperationState', - [this.operation.id, OperationState.Ready], + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], ); }); @@ -408,7 +409,7 @@ contract('TimelockController', function (accounts) { { from: executor }, ), 'TimelockUnexpectedOperationState', - [reentrantOperation.id, OperationState.Ready], + [reentrantOperation.id, proposalStatesToBitMap(OperationState.Ready)], ); // Disable reentrancy @@ -505,7 +506,7 @@ contract('TimelockController', function (accounts) { { from: proposer }, ), 'TimelockUnexpectedOperationState', - [this.operation.id, OperationState.Unset], + [this.operation.id, proposalStatesToBitMap(OperationState.Unset)], ); }); @@ -596,7 +597,7 @@ contract('TimelockController', function (accounts) { { from: executor }, ), 'TimelockUnexpectedOperationState', - [this.operation.id, OperationState.Ready], + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], ); }); @@ -624,7 +625,7 @@ contract('TimelockController', function (accounts) { { from: executor }, ), 'TimelockUnexpectedOperationState', - [this.operation.id, OperationState.Ready], + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], ); }); @@ -642,7 +643,7 @@ contract('TimelockController', function (accounts) { { from: executor }, ), 'TimelockUnexpectedOperationState', - [this.operation.id, OperationState.Ready], + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], ); }); @@ -784,7 +785,7 @@ contract('TimelockController', function (accounts) { { from: executor }, ), 'TimelockUnexpectedOperationState', - [reentrantBatchOperation.id, OperationState.Ready], + [reentrantBatchOperation.id, proposalStatesToBitMap(OperationState.Ready)], ); // Disable reentrancy @@ -881,7 +882,7 @@ contract('TimelockController', function (accounts) { await expectRevertCustomError( this.mock.cancel(constants.ZERO_BYTES32, { from: canceller }), 'TimelockUnexpectedOperationState', - [constants.ZERO_BYTES32, OperationState.Pending], + [constants.ZERO_BYTES32, proposalStatesToBitMap([OperationState.Waiting, OperationState.Ready])], ); }); diff --git a/test/governance/extensions/GovernorTimelockControl.test.js b/test/governance/extensions/GovernorTimelockControl.test.js index 3265dfa68..5954d4117 100644 --- a/test/governance/extensions/GovernorTimelockControl.test.js +++ b/test/governance/extensions/GovernorTimelockControl.test.js @@ -159,7 +159,7 @@ contract('GovernorTimelockControl', function (accounts) { await expectRevertCustomError(this.helper.execute(), 'TimelockUnexpectedOperationState', [ this.proposal.timelockid, - Enums.OperationState.Ready, + proposalStatesToBitMap(Enums.OperationState.Ready), ]); }); @@ -174,7 +174,7 @@ contract('GovernorTimelockControl', function (accounts) { await expectRevertCustomError(this.helper.execute(), 'TimelockUnexpectedOperationState', [ this.proposal.timelockid, - Enums.OperationState.Ready, + proposalStatesToBitMap(Enums.OperationState.Ready), ]); }); diff --git a/test/helpers/enums.js b/test/helpers/enums.js index d4a4fdbd0..75746e087 100644 --- a/test/helpers/enums.js +++ b/test/helpers/enums.js @@ -7,5 +7,5 @@ module.exports = { ProposalState: Enum('Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'), VoteType: Enum('Against', 'For', 'Abstain'), Rounding: Enum('Down', 'Up', 'Zero'), - OperationState: Enum('Unset', 'Pending', 'Ready', 'Done'), + OperationState: Enum('Unset', 'Waiting', 'Ready', 'Done'), }; From 90163661df4f7df22294fcbf82dd3f6bb5547417 Mon Sep 17 00:00:00 2001 From: Renan Souza Date: Tue, 4 Jul 2023 15:40:41 -0300 Subject: [PATCH 11/16] Implement ERC165 tests realted to invalidID (#4414) Co-authored-by: ernestognw --- .../SupportsInterface.behavior.js | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/test/utils/introspection/SupportsInterface.behavior.js b/test/utils/introspection/SupportsInterface.behavior.js index 71be4313f..9c0fd0848 100644 --- a/test/utils/introspection/SupportsInterface.behavior.js +++ b/test/utils/introspection/SupportsInterface.behavior.js @@ -2,6 +2,7 @@ const { makeInterfaceId } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); +const INVALID_ID = '0xffffffff'; const INTERFACES = { ERC165: ['supportsInterface(bytes4)'], ERC721: [ @@ -111,18 +112,30 @@ function shouldSupportInterfaces(interfaces = []) { this.contractUnderTest = this.mock || this.token || this.holder || this.accessControl; }); - it('supportsInterface uses less than 30k gas', async function () { - for (const k of interfaces) { - const interfaceId = INTERFACE_IDS[k] ?? k; - expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.be.lte(30000); - } + describe('when the interfaceId is supported', function () { + it('uses less than 30k gas', async function () { + for (const k of interfaces) { + const interfaceId = INTERFACE_IDS[k] ?? k; + expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.be.lte(30000); + } + }); + + it('returns true', async function () { + for (const k of interfaces) { + const interfaceId = INTERFACE_IDS[k] ?? k; + expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true, `does not support ${k}`); + } + }); }); - it('all interfaces are reported as supported', async function () { - for (const k of interfaces) { - const interfaceId = INTERFACE_IDS[k] ?? k; - expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true, `does not support ${k}`); - } + describe('when the interfaceId is not supported', function () { + it('uses less thank 30k', async function () { + expect(await this.contractUnderTest.supportsInterface.estimateGas(INVALID_ID)).to.be.lte(30000); + }); + + it('returns false', async function () { + expect(await this.contractUnderTest.supportsInterface(INVALID_ID)).to.be.equal(false, `supports ${INVALID_ID}`); + }); }); it('all interface functions are in ABI', async function () { From 63bfab1a0ce40d14f33f6354ff5ebcd67a76f143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Wed, 5 Jul 2023 07:11:29 -0600 Subject: [PATCH 12/16] Enable ERC-1271 signature checks in Governor `castVoteBySig` (#4418) Co-authored-by: Hadrien Croubois Co-authored-by: Francisco --- .changeset/popular-deers-raise.md | 5 + contracts/governance/Governor.sol | 36 ++-- contracts/governance/IGovernor.sol | 18 +- .../utils/cryptography/SignatureChecker.sol | 2 +- test/governance/Governor.test.js | 179 +++++++++++------- .../extensions/GovernorWithParams.test.js | 96 +++++++--- test/helpers/governance.js | 8 +- .../SupportsInterface.behavior.js | 6 +- 8 files changed, 213 insertions(+), 137 deletions(-) create mode 100644 .changeset/popular-deers-raise.md diff --git a/.changeset/popular-deers-raise.md b/.changeset/popular-deers-raise.md new file mode 100644 index 000000000..ec1fb7466 --- /dev/null +++ b/.changeset/popular-deers-raise.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': major +--- + +`Governor`: Add support for casting votes with ERC-1271 signatures by using a `bytes memory signature` instead of `r`, `s` and `v` arguments in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index 1e1526ceb..ef730d3f7 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -5,8 +5,8 @@ pragma solidity ^0.8.19; import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; -import {ECDSA} from "../utils/cryptography/ECDSA.sol"; import {EIP712} from "../utils/cryptography/EIP712.sol"; +import {SignatureChecker} from "../utils/cryptography/SignatureChecker.sol"; import {IERC165, ERC165} from "../utils/introspection/ERC165.sol"; import {SafeCast} from "../utils/math/SafeCast.sol"; import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; @@ -519,22 +519,19 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72 uint256 proposalId, uint8 support, address voter, - uint8 v, - bytes32 r, - bytes32 s + bytes memory signature ) public virtual override returns (uint256) { - address signer = ECDSA.recover( + bool valid = SignatureChecker.isValidSignatureNow( + voter, _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter)))), - v, - r, - s + signature ); - if (voter != signer) { - revert GovernorInvalidSigner(signer, voter); + if (!valid) { + revert GovernorInvalidSignature(voter); } - return _castVote(proposalId, signer, support, ""); + return _castVote(proposalId, voter, support, ""); } /** @@ -546,11 +543,10 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72 address voter, string calldata reason, bytes memory params, - uint8 v, - bytes32 r, - bytes32 s + bytes memory signature ) public virtual override returns (uint256) { - address signer = ECDSA.recover( + bool valid = SignatureChecker.isValidSignatureNow( + voter, _hashTypedDataV4( keccak256( abi.encode( @@ -564,16 +560,14 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72 ) ) ), - v, - r, - s + signature ); - if (voter != signer) { - revert GovernorInvalidSigner(signer, voter); + if (!valid) { + revert GovernorInvalidSignature(voter); } - return _castVote(proposalId, signer, support, reason, params); + return _castVote(proposalId, voter, support, reason, params); } /** diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index 20636e3ba..af4698226 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -81,9 +81,10 @@ abstract contract IGovernor is IERC165, IERC6372 { error GovernorInvalidVoteType(); /** - * @dev The `voter` doesn't match with the recovered `signer`. + * @dev The provided signature is not valid for the expected `voter`. + * If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}. */ - error GovernorInvalidSigner(address signer, address voter); + error GovernorInvalidSignature(address voter); /** * @dev Emitted when a proposal is created. @@ -353,7 +354,7 @@ abstract contract IGovernor is IERC165, IERC6372 { ) public virtual returns (uint256 balance); /** - * @dev Cast a vote using the user's cryptographic signature. + * @dev Cast a vote using the voter's signature, including ERC-1271 signature support. * * Emits a {VoteCast} event. */ @@ -361,13 +362,12 @@ abstract contract IGovernor is IERC165, IERC6372 { uint256 proposalId, uint8 support, address voter, - uint8 v, - bytes32 r, - bytes32 s + bytes memory signature ) public virtual returns (uint256 balance); /** - * @dev Cast a vote with a reason and additional encoded parameters using the user's cryptographic signature. + * @dev Cast a vote with a reason and additional encoded parameters using the voter's signature, + * including ERC-1271 signature support. * * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. */ @@ -377,8 +377,6 @@ abstract contract IGovernor is IERC165, IERC6372 { address voter, string calldata reason, bytes memory params, - uint8 v, - bytes32 r, - bytes32 s + bytes memory signature ) public virtual returns (uint256 balance); } diff --git a/contracts/utils/cryptography/SignatureChecker.sol b/contracts/utils/cryptography/SignatureChecker.sol index dfc512b39..5caf7bef9 100644 --- a/contracts/utils/cryptography/SignatureChecker.sol +++ b/contracts/utils/cryptography/SignatureChecker.sol @@ -9,7 +9,7 @@ import {IERC1271} from "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like - * Argent and Gnosis Safe. + * Argent and Safe Wallet (previously Gnosis Safe). * * _Available since v4.1._ */ diff --git a/test/governance/Governor.test.js b/test/governance/Governor.test.js index f4a352c6d..4e47ab9f2 100644 --- a/test/governance/Governor.test.js +++ b/test/governance/Governor.test.js @@ -2,7 +2,6 @@ const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-hel const { expect } = require('chai'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { fromRpcSig, toRpcSig } = require('ethereumjs-util'); const Enums = require('../helpers/enums'); const { getDomain, domainType } = require('../helpers/eip712'); @@ -18,6 +17,7 @@ const Governor = artifacts.require('$GovernorMock'); const CallReceiver = artifacts.require('CallReceiverMock'); const ERC721 = artifacts.require('$ERC721'); const ERC1155 = artifacts.require('$ERC1155'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); const TOKENS = [ { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, @@ -166,55 +166,6 @@ contract('Governor', function (accounts) { expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value); }); - it('votes with signature', async function () { - const voterBySig = Wallet.generate(); - const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); - - const signature = (contract, message) => - getDomain(contract) - .then(domain => ({ - primaryType: 'Ballot', - types: { - EIP712Domain: domainType(domain), - Ballot: [ - { name: 'proposalId', type: 'uint256' }, - { name: 'support', type: 'uint8' }, - { name: 'voter', type: 'address' }, - { name: 'nonce', type: 'uint256' }, - ], - }, - domain, - message, - })) - .then(data => ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { data })) - .then(fromRpcSig); - - await this.token.delegate(voterBySigAddress, { from: voter1 }); - - const nonce = await this.mock.nonces(voterBySigAddress); - - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - expectEvent( - await this.helper.vote({ support: Enums.VoteType.For, voter: voterBySigAddress, nonce, signature }), - 'VoteCast', - { - voter: voterBySigAddress, - support: Enums.VoteType.For, - }, - ); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - // After - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voterBySigAddress)).to.be.equal(true); - expect(await this.mock.nonces(voterBySigAddress)).to.be.bignumber.equal(nonce.addn(1)); - }); - it('send ethers', async function () { const empty = web3.utils.toChecksumAddress(web3.utils.randomHex(20)); @@ -244,6 +195,106 @@ contract('Governor', function (accounts) { expect(await web3.eth.getBalance(empty)).to.be.bignumber.equal(value); }); + describe('vote with signature', function () { + const sign = privateKey => async (contract, message) => { + const domain = await getDomain(contract); + return ethSigUtil.signTypedMessage(privateKey, { + data: { + primaryType: 'Ballot', + types: { + EIP712Domain: domainType(domain), + Ballot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + ], + }, + domain, + message, + }, + }); + }; + + afterEach('no other votes are cast for proposalId', async function () { + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); + }); + + it('votes with an EOA signature', async function () { + const voterBySig = Wallet.generate(); + const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); + + await this.token.delegate(voterBySigAddress, { from: voter1 }); + + const nonce = await this.mock.nonces(voterBySigAddress); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + expectEvent( + await this.helper.vote({ + support: Enums.VoteType.For, + voter: voterBySigAddress, + nonce, + signature: sign(voterBySig.getPrivateKey()), + }), + 'VoteCast', + { + voter: voterBySigAddress, + support: Enums.VoteType.For, + }, + ); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, voterBySigAddress)).to.be.equal(true); + expect(await this.mock.nonces(voterBySigAddress)).to.be.bignumber.equal(nonce.addn(1)); + }); + + it('votes with a valid EIP-1271 signature', async function () { + const ERC1271WalletOwner = Wallet.generate(); + ERC1271WalletOwner.address = web3.utils.toChecksumAddress(ERC1271WalletOwner.getAddressString()); + + const wallet = await ERC1271WalletMock.new(ERC1271WalletOwner.address); + + await this.token.delegate(wallet.address, { from: voter1 }); + + const nonce = await this.mock.nonces(wallet.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + expectEvent( + await this.helper.vote({ + support: Enums.VoteType.For, + voter: wallet.address, + nonce, + signature: sign(ERC1271WalletOwner.getPrivateKey()), + }), + 'VoteCast', + { + voter: wallet.address, + support: Enums.VoteType.For, + }, + ); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, wallet.address)).to.be.equal(true); + expect(await this.mock.nonces(wallet.address)).to.be.bignumber.equal(nonce.addn(1)); + }); + + afterEach('no other votes are cast', async function () { + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); + }); + }); + describe('should revert', function () { describe('on propose', function () { it('if proposal already exists', async function () { @@ -328,9 +379,9 @@ contract('Governor', function (accounts) { })); this.signature = (contract, message) => - this.data(contract, message) - .then(data => ethSigUtil.signTypedMessage(this.voterBySig.getPrivateKey(), { data })) - .then(fromRpcSig); + this.data(contract, message).then(data => + ethSigUtil.signTypedMessage(this.voterBySig.getPrivateKey(), { data }), + ); await this.token.delegate(this.voterBySig.address, { from: voter1 }); @@ -348,19 +399,13 @@ contract('Governor', function (accounts) { nonce, signature: async (...params) => { const sig = await this.signature(...params); - sig.s[12] ^= 0xff; - return sig; + const tamperedSig = web3.utils.hexToBytes(sig); + tamperedSig[42] ^= 0xff; + return web3.utils.bytesToHex(tamperedSig); }, }; - const { r, s, v } = await this.helper.sign(voteParams); - const message = this.helper.forgeMessage(voteParams); - const data = await this.data(this.mock, message); - - await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSigner', [ - ethSigUtil.recoverTypedSignature({ sig: toRpcSig(v, r, s), data }), - voteParams.voter, - ]); + await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSignature', [voteParams.voter]); }); it('if vote nonce is incorrect', async function () { @@ -373,15 +418,11 @@ contract('Governor', function (accounts) { signature: this.signature, }; - const { r, s, v } = await this.helper.sign(voteParams); - const message = this.helper.forgeMessage(voteParams); - const data = await this.data(this.mock, { ...message, nonce }); - await expectRevertCustomError( this.helper.vote(voteParams), // The signature check implies the nonce can't be tampered without changing the signer - 'GovernorInvalidSigner', - [ethSigUtil.recoverTypedSignature({ sig: toRpcSig(v, r, s), data }), voteParams.voter], + 'GovernorInvalidSignature', + [voteParams.voter], ); }); }); diff --git a/test/governance/extensions/GovernorWithParams.test.js b/test/governance/extensions/GovernorWithParams.test.js index fb58edaaf..896c2e094 100644 --- a/test/governance/extensions/GovernorWithParams.test.js +++ b/test/governance/extensions/GovernorWithParams.test.js @@ -2,7 +2,6 @@ const { expectEvent } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { fromRpcSig, toRpcSig } = require('ethereumjs-util'); const Enums = require('../../helpers/enums'); const { getDomain, domainType } = require('../../helpers/eip712'); @@ -11,6 +10,7 @@ const { expectRevertCustomError } = require('../../helpers/customError'); const Governor = artifacts.require('$GovernorWithParamsMock'); const CallReceiver = artifacts.require('CallReceiverMock'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); const rawParams = { uintParam: web3.utils.toBN('42'), @@ -143,35 +143,71 @@ contract('GovernorWithParams', function (accounts) { message, })); - this.signature = (contract, message) => - this.data(contract, message) - .then(data => ethSigUtil.signTypedMessage(this.voterBySig.getPrivateKey(), { data })) - .then(fromRpcSig); + this.sign = privateKey => async (contract, message) => + ethSigUtil.signTypedMessage(privateKey, { data: await this.data(contract, message) }); + }); + it('suports EOA signatures', async function () { await this.token.delegate(this.voterBySig.address, { from: voter2 }); + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); + + const nonce = await this.mock.nonces(this.voterBySig.address); + // Run proposal await this.helper.propose(); await this.helper.waitForSnapshot(); + const tx = await this.helper.vote({ + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + reason: 'no particular reason', + params: encodedParams, + signature: this.sign(this.voterBySig.getPrivateKey()), + }); + + expectEvent(tx, 'CountParams', { ...rawParams }); + expectEvent(tx, 'VoteCastWithParams', { + voter: this.voterBySig.address, + proposalId: this.proposal.id, + support: Enums.VoteType.For, + weight, + reason: 'no particular reason', + params: encodedParams, + }); + + const votes = await this.mock.proposalVotes(this.proposal.id); + expect(votes.forVotes).to.be.bignumber.equal(weight); + expect(await this.mock.nonces(this.voterBySig.address)).to.be.bignumber.equal(nonce.addn(1)); }); - it('is properly supported', async function () { + it('supports EIP-1271 signature signatures', async function () { + const ERC1271WalletOwner = Wallet.generate(); + ERC1271WalletOwner.address = web3.utils.toChecksumAddress(ERC1271WalletOwner.getAddressString()); + + const wallet = await ERC1271WalletMock.new(ERC1271WalletOwner.address); + + await this.token.delegate(wallet.address, { from: voter2 }); + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); - const nonce = await this.mock.nonces(this.voterBySig.address); + const nonce = await this.mock.nonces(wallet.address); + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); const tx = await this.helper.vote({ support: Enums.VoteType.For, - voter: this.voterBySig.address, + voter: wallet.address, nonce, reason: 'no particular reason', params: encodedParams, - signature: this.signature, + signature: this.sign(ERC1271WalletOwner.getPrivateKey()), }); expectEvent(tx, 'CountParams', { ...rawParams }); expectEvent(tx, 'VoteCastWithParams', { - voter: this.voterBySig.address, + voter: wallet.address, proposalId: this.proposal.id, support: Enums.VoteType.For, weight, @@ -181,56 +217,58 @@ contract('GovernorWithParams', function (accounts) { const votes = await this.mock.proposalVotes(this.proposal.id); expect(votes.forVotes).to.be.bignumber.equal(weight); - expect(await this.mock.nonces(this.voterBySig.address)).to.be.bignumber.equal(nonce.addn(1)); + expect(await this.mock.nonces(wallet.address)).to.be.bignumber.equal(nonce.addn(1)); }); it('reverts if signature does not match signer', async function () { + await this.token.delegate(this.voterBySig.address, { from: voter2 }); + const nonce = await this.mock.nonces(this.voterBySig.address); + const signature = this.sign(this.voterBySig.getPrivateKey()); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); const voteParams = { support: Enums.VoteType.For, voter: this.voterBySig.address, nonce, signature: async (...params) => { - const sig = await this.signature(...params); - sig.s[12] ^= 0xff; - return sig; + const sig = await signature(...params); + const tamperedSig = web3.utils.hexToBytes(sig); + tamperedSig[42] ^= 0xff; + return web3.utils.bytesToHex(tamperedSig); }, reason: 'no particular reason', params: encodedParams, }; - const { r, s, v } = await this.helper.sign(voteParams); - const message = this.helper.forgeMessage(voteParams); - const data = await this.data(this.mock, message); - - await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSigner', [ - ethSigUtil.recoverTypedSignature({ sig: toRpcSig(v, r, s), data }), - voteParams.voter, - ]); + await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSignature', [voteParams.voter]); }); it('reverts if vote nonce is incorrect', async function () { + await this.token.delegate(this.voterBySig.address, { from: voter2 }); + const nonce = await this.mock.nonces(this.voterBySig.address); + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); const voteParams = { support: Enums.VoteType.For, voter: this.voterBySig.address, nonce: nonce.addn(1), - signature: this.signature, + signature: this.sign(this.voterBySig.getPrivateKey()), reason: 'no particular reason', params: encodedParams, }; - const { r, s, v } = await this.helper.sign(voteParams); - const message = this.helper.forgeMessage(voteParams); - const data = await this.data(this.mock, { ...message, nonce }); - await expectRevertCustomError( this.helper.vote(voteParams), // The signature check implies the nonce can't be tampered without changing the signer - 'GovernorInvalidSigner', - [ethSigUtil.recoverTypedSignature({ sig: toRpcSig(v, r, s), data }), voteParams.voter], + 'GovernorInvalidSignature', + [voteParams.voter], ); }); }); diff --git a/test/helpers/governance.js b/test/helpers/governance.js index 588aeb258..3ae0695ac 100644 --- a/test/helpers/governance.js +++ b/test/helpers/governance.js @@ -91,16 +91,16 @@ class GovernorHelper { return vote.signature ? // if signature, and either params or reason → vote.params || vote.reason - ? this.sign(vote).then(({ v, r, s }) => + ? this.sign(vote).then(signature => this.governor.castVoteWithReasonAndParamsBySig( ...concatOpts( - [proposal.id, vote.support, vote.voter, vote.reason || '', vote.params || '', v, r, s], + [proposal.id, vote.support, vote.voter, vote.reason || '', vote.params || '', signature], opts, ), ), ) - : this.sign(vote).then(({ v, r, s }) => - this.governor.castVoteBySig(...concatOpts([proposal.id, vote.support, vote.voter, v, r, s], opts)), + : this.sign(vote).then(signature => + this.governor.castVoteBySig(...concatOpts([proposal.id, vote.support, vote.voter, signature], opts)), ) : vote.params ? // otherwise if params diff --git a/test/utils/introspection/SupportsInterface.behavior.js b/test/utils/introspection/SupportsInterface.behavior.js index 9c0fd0848..80e144f18 100644 --- a/test/utils/introspection/SupportsInterface.behavior.js +++ b/test/utils/introspection/SupportsInterface.behavior.js @@ -67,7 +67,7 @@ const INTERFACES = { 'execute(address[],uint256[],bytes[],bytes32)', 'castVote(uint256,uint8)', 'castVoteWithReason(uint256,uint8,string)', - 'castVoteBySig(uint256,uint8,address,uint8,bytes32,bytes32)', + 'castVoteBySig(uint256,uint8,address,bytes)', ], GovernorWithParams: [ 'name()', @@ -88,8 +88,8 @@ const INTERFACES = { 'castVote(uint256,uint8)', 'castVoteWithReason(uint256,uint8,string)', 'castVoteWithReasonAndParams(uint256,uint8,string,bytes)', - 'castVoteBySig(uint256,uint8,address,uint8,bytes32,bytes32)', - 'castVoteWithReasonAndParamsBySig(uint256,uint8,address,string,bytes,uint8,bytes32,bytes32)', + 'castVoteBySig(uint256,uint8,address,bytes)', + 'castVoteWithReasonAndParamsBySig(uint256,uint8,address,string,bytes,bytes)', ], GovernorCancel: ['proposalProposer(uint256)', 'cancel(address[],uint256[],bytes[],bytes32)'], GovernorTimelock: ['timelock()', 'proposalEta(uint256)', 'queue(address[],uint256[],bytes[],bytes32)'], From 3ff9b42ff57f5bbb25a85481007a7dbac4bbc705 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 5 Jul 2023 18:38:27 -0300 Subject: [PATCH 13/16] Remove retyped and renamed storage layout annotations (#4423) --- contracts/governance/Governor.sol | 1 - .../extensions/GovernorPreventLateQuorum.sol | 1 - .../extensions/GovernorTimelockCompound.sol | 1 - .../GovernorVotesQuorumFraction.sol | 1 - contracts/governance/utils/Votes.sol | 2 - contracts/proxy/utils/Initializable.sol | 1 - scripts/upgradeable/upgradeable.patch | 79 ++----------------- 7 files changed, 7 insertions(+), 79 deletions(-) diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index ef730d3f7..a66a1a6bf 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -49,7 +49,6 @@ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC72 bytes32 private constant _ALL_PROPOSAL_STATES_BITMAP = bytes32((2 ** (uint8(type(ProposalState).max) + 1)) - 1); string private _name; - /// @custom:oz-retyped-from mapping(uint256 => Governor.ProposalCore) mapping(uint256 => ProposalCore) private _proposals; // This queue keeps track of the governor operating on itself. Calls to functions protected by the diff --git a/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/contracts/governance/extensions/GovernorPreventLateQuorum.sol index 3e034acad..8687b6fd1 100644 --- a/contracts/governance/extensions/GovernorPreventLateQuorum.sol +++ b/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -20,7 +20,6 @@ import {Math} from "../../utils/math/Math.sol"; abstract contract GovernorPreventLateQuorum is Governor { uint48 private _voteExtension; - /// @custom:oz-retyped-from mapping(uint256 => Timers.BlockNumber) mapping(uint256 => uint48) private _extendedDeadlines; /// @dev Emitted when a proposal deadline is pushed back due to reaching quorum late in its voting period. diff --git a/contracts/governance/extensions/GovernorTimelockCompound.sol b/contracts/governance/extensions/GovernorTimelockCompound.sol index cd61d1ff8..935600d56 100644 --- a/contracts/governance/extensions/GovernorTimelockCompound.sol +++ b/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -25,7 +25,6 @@ import {Address} from "../../utils/Address.sol"; abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { ICompoundTimelock private _timelock; - /// @custom:oz-retyped-from mapping(uint256 => GovernorTimelockCompound.ProposalTimelock) mapping(uint256 => uint256) private _proposalTimelocks; /** diff --git a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol index bb1c7d2ea..5d7976b14 100644 --- a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol +++ b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -16,7 +16,6 @@ import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; abstract contract GovernorVotesQuorumFraction is GovernorVotes { using Checkpoints for Checkpoints.Trace224; - /// @custom:oz-retyped-from Checkpoints.History Checkpoints.Trace224 private _quorumNumeratorHistory; event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator); diff --git a/contracts/governance/utils/Votes.sol b/contracts/governance/utils/Votes.sol index c0ff69e62..988255189 100644 --- a/contracts/governance/utils/Votes.sol +++ b/contracts/governance/utils/Votes.sol @@ -38,10 +38,8 @@ abstract contract Votes is Context, EIP712, Nonces, IERC5805 { mapping(address => address) private _delegation; - /// @custom:oz-retyped-from mapping(address => Checkpoints.History) mapping(address => Checkpoints.Trace224) private _delegateCheckpoints; - /// @custom:oz-retyped-from Checkpoints.History Checkpoints.Trace224 private _totalCheckpoints; /** diff --git a/contracts/proxy/utils/Initializable.sol b/contracts/proxy/utils/Initializable.sol index 86e99531b..a2e3569c4 100644 --- a/contracts/proxy/utils/Initializable.sol +++ b/contracts/proxy/utils/Initializable.sol @@ -58,7 +58,6 @@ import {Address} from "../../utils/Address.sol"; abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. - * @custom:oz-retyped-from bool */ uint8 private _initialized; diff --git a/scripts/upgradeable/upgradeable.patch b/scripts/upgradeable/upgradeable.patch index 466d1d1ca..8623806f5 100644 --- a/scripts/upgradeable/upgradeable.patch +++ b/scripts/upgradeable/upgradeable.patch @@ -105,32 +105,6 @@ index 27627f43..e42a66e8 100644 } } ``` -diff --git a/contracts/finance/VestingWallet.sol b/contracts/finance/VestingWallet.sol -index f776a7ca..d7a7e0b0 100644 ---- a/contracts/finance/VestingWallet.sol -+++ b/contracts/finance/VestingWallet.sol -@@ -19,6 +19,8 @@ import {Context} from "../utils/Context.sol"; - * - * By setting the duration to 0, one can configure this contract to behave like an asset timelock that hold tokens for - * a beneficiary until a specified time. -+ * -+ * @custom:storage-size 52 - */ - contract VestingWallet is Context { - event EtherReleased(uint256 amount); -diff --git a/contracts/governance/extensions/GovernorVotes.sol b/contracts/governance/extensions/GovernorVotes.sol -index bb14d7fd..0785ebbd 100644 ---- a/contracts/governance/extensions/GovernorVotes.sol -+++ b/contracts/governance/extensions/GovernorVotes.sol -@@ -12,6 +12,8 @@ import {SafeCast} from "../../utils/math/SafeCast.sol"; - * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} token. - * - * _Available since v4.3._ -+ * -+ * @custom:storage-size 51 - */ - abstract contract GovernorVotes is Governor { - IERC5805 public immutable token; diff --git a/contracts/package.json b/contracts/package.json index df141192..1cf90ad1 100644 --- a/contracts/package.json @@ -151,47 +125,8 @@ index df141192..1cf90ad1 100644 }, "keywords": [ "solidity", -diff --git a/contracts/token/ERC20/extensions/ERC20Capped.sol b/contracts/token/ERC20/extensions/ERC20Capped.sol -index 98ec7144..4992115b 100644 ---- a/contracts/token/ERC20/extensions/ERC20Capped.sol -+++ b/contracts/token/ERC20/extensions/ERC20Capped.sol -@@ -7,6 +7,8 @@ import {ERC20} from "../ERC20.sol"; - - /** - * @dev Extension of {ERC20} that adds a cap to the supply of tokens. -+ * -+ * @custom:storage-size 51 - */ - abstract contract ERC20Capped is ERC20 { - uint256 private immutable _cap; -diff --git a/contracts/token/ERC20/extensions/ERC20Permit.sol b/contracts/token/ERC20/extensions/ERC20Permit.sol -index 8778f4ba..825d4e16 100644 ---- a/contracts/token/ERC20/extensions/ERC20Permit.sol -+++ b/contracts/token/ERC20/extensions/ERC20Permit.sol -@@ -18,6 +18,8 @@ import {Nonces} from "../../../utils/Nonces.sol"; - * need to send a transaction, and thus is not required to hold Ether at all. - * - * _Available since v3.4._ -+ * -+ * @custom:storage-size 51 - */ - abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces { - // solhint-disable-next-line var-name-mixedcase -diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol -index 2cbff622..97f43d7a 100644 ---- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol -+++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol -@@ -14,6 +14,8 @@ import {SafeERC20} from "../utils/SafeERC20.sol"; - * wrapping of an existing "basic" ERC20 into a governance token. - * - * _Available since v4.2._ -+ * -+ * @custom:storage-size 51 - */ - abstract contract ERC20Wrapper is ERC20 { - IERC20 private immutable _underlying; diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol -index d94e956a..86bb5713 100644 +index d94e956a..b2d3546f 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -4,7 +4,6 @@ @@ -202,12 +137,12 @@ index d94e956a..86bb5713 100644 import {IERC5267} from "../../interfaces/IERC5267.sol"; /** -@@ -30,27 +29,19 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; +@@ -29,28 +28,18 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; + * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ - * +- * - * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment -+ * @custom:storage-size 52 */ abstract contract EIP712 is IERC5267 { - using ShortStrings for *; @@ -235,7 +170,7 @@ index d94e956a..86bb5713 100644 /** * @dev Initializes the domain separator and parameter caches. -@@ -65,29 +56,23 @@ abstract contract EIP712 is IERC5267 { +@@ -65,29 +54,23 @@ abstract contract EIP712 is IERC5267 { * contract upgrade]. */ constructor(string memory name, string memory version) { @@ -273,7 +208,7 @@ index d94e956a..86bb5713 100644 } /** -@@ -128,6 +113,10 @@ abstract contract EIP712 is IERC5267 { +@@ -128,6 +111,10 @@ abstract contract EIP712 is IERC5267 { uint256[] memory extensions ) { @@ -284,7 +219,7 @@ index d94e956a..86bb5713 100644 return ( hex"0f", // 01111 _EIP712Name(), -@@ -142,26 +131,62 @@ abstract contract EIP712 is IERC5267 { +@@ -142,26 +129,62 @@ abstract contract EIP712 is IERC5267 { /** * @dev The name parameter for the EIP712 domain. * From 3fe28e19af0152782f5e1951ad41c1724bd06f03 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 00:14:20 -0300 Subject: [PATCH 14/16] Update lockfile (#4409) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 760 +++++++++++++++++++++------------------------- 1 file changed, 353 insertions(+), 407 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e6296d24..3f9a4f5da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,34 +51,43 @@ "yargs": "^17.0.0" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -87,9 +96,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz", - "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dev": true, "dependencies": { "regenerator-runtime": "^0.13.11" @@ -125,13 +134,13 @@ } }, "node_modules/@changesets/apply-release-plan": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.3.tgz", - "integrity": "sha512-ECDNeoc3nfeAe1jqJb5aFQX7CqzQhD2klXRez2JDb/aVpGUbX673HgKrnrgJRuQR/9f2TtLoYIzrGB9qwD77mg==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.4.tgz", + "integrity": "sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==", "dev": true, "dependencies": { "@babel/runtime": "^7.20.1", - "@changesets/config": "^2.3.0", + "@changesets/config": "^2.3.1", "@changesets/get-version-range-type": "^0.3.2", "@changesets/git": "^2.0.0", "@changesets/types": "^5.2.1", @@ -142,39 +151,21 @@ "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", - "semver": "^5.4.1" - } - }, - "node_modules/@changesets/apply-release-plan/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" + "semver": "^7.5.3" } }, "node_modules/@changesets/assemble-release-plan": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.3.tgz", - "integrity": "sha512-g7EVZCmnWz3zMBAdrcKhid4hkHT+Ft1n0mLussFMcB1dE2zCuwcvGoy9ec3yOgPGF4hoMtgHaMIk3T3TBdvU9g==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.4.tgz", + "integrity": "sha512-xJkWX+1/CUaOUWTguXEbCDTyWJFECEhmdtbkjhn5GVBGxdP/JwaHBIU9sW3FR6gD07UwZ7ovpiPclQZs+j+mvg==", "dev": true, "dependencies": { "@babel/runtime": "^7.20.1", "@changesets/errors": "^0.1.4", - "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/get-dependents-graph": "^1.3.6", "@changesets/types": "^5.2.1", "@manypkg/get-packages": "^1.1.3", - "semver": "^5.4.1" - } - }, - "node_modules/@changesets/assemble-release-plan/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" + "semver": "^7.5.3" } }, "node_modules/@changesets/changelog-git": { @@ -198,19 +189,19 @@ } }, "node_modules/@changesets/cli": { - "version": "2.26.1", - "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.1.tgz", - "integrity": "sha512-XnTa+b51vt057fyAudvDKGB0Sh72xutQZNAdXkCqPBKO2zvs2yYZx5hFZj1u9cbtpwM6Sxtcr02/FQJfZOzemQ==", + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.2.tgz", + "integrity": "sha512-dnWrJTmRR8bCHikJHl9b9HW3gXACCehz4OasrXpMp7sx97ECuBGGNjJhjPhdZNCvMy9mn4BWdplI323IbqsRig==", "dev": true, "dependencies": { "@babel/runtime": "^7.20.1", - "@changesets/apply-release-plan": "^6.1.3", - "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/apply-release-plan": "^6.1.4", + "@changesets/assemble-release-plan": "^5.2.4", "@changesets/changelog-git": "^0.1.14", - "@changesets/config": "^2.3.0", + "@changesets/config": "^2.3.1", "@changesets/errors": "^0.1.4", - "@changesets/get-dependents-graph": "^1.3.5", - "@changesets/get-release-plan": "^3.0.16", + "@changesets/get-dependents-graph": "^1.3.6", + "@changesets/get-release-plan": "^3.0.17", "@changesets/git": "^2.0.0", "@changesets/logger": "^0.0.5", "@changesets/pre": "^1.0.14", @@ -219,7 +210,7 @@ "@changesets/write": "^0.2.3", "@manypkg/get-packages": "^1.1.3", "@types/is-ci": "^3.0.0", - "@types/semver": "^6.0.0", + "@types/semver": "^7.5.0", "ansi-colors": "^4.1.3", "chalk": "^2.1.0", "enquirer": "^2.3.0", @@ -232,7 +223,7 @@ "p-limit": "^2.2.0", "preferred-pm": "^3.0.0", "resolve-from": "^5.0.0", - "semver": "^5.4.1", + "semver": "^7.5.3", "spawndamnit": "^2.0.0", "term-size": "^2.1.0", "tty-table": "^4.1.5" @@ -256,23 +247,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@changesets/cli/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/@changesets/config": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.0.tgz", - "integrity": "sha512-EgP/px6mhCx8QeaMAvWtRrgyxW08k/Bx2tpGT+M84jEdX37v3VKfh4Cz1BkwrYKuMV2HZKeHOh8sHvja/HcXfQ==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.1.tgz", + "integrity": "sha512-PQXaJl82CfIXddUOppj4zWu+987GCw2M+eQcOepxN5s+kvnsZOwjEJO3DH9eVy+OP6Pg/KFEWdsECFEYTtbg6w==", "dev": true, "dependencies": { "@changesets/errors": "^0.1.4", - "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/get-dependents-graph": "^1.3.6", "@changesets/logger": "^0.0.5", "@changesets/types": "^5.2.1", "@manypkg/get-packages": "^1.1.3", @@ -290,25 +272,16 @@ } }, "node_modules/@changesets/get-dependents-graph": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.5.tgz", - "integrity": "sha512-w1eEvnWlbVDIY8mWXqWuYE9oKhvIaBhzqzo4ITSJY9hgoqQ3RoBqwlcAzg11qHxv/b8ReDWnMrpjpKrW6m1ZTA==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.6.tgz", + "integrity": "sha512-Q/sLgBANmkvUm09GgRsAvEtY3p1/5OCzgBE5vX3vgb5CvW0j7CEljocx5oPXeQSNph6FXulJlXV3Re/v3K3P3Q==", "dev": true, "dependencies": { "@changesets/types": "^5.2.1", "@manypkg/get-packages": "^1.1.3", "chalk": "^2.1.0", "fs-extra": "^7.0.1", - "semver": "^5.4.1" - } - }, - "node_modules/@changesets/get-dependents-graph/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" + "semver": "^7.5.3" } }, "node_modules/@changesets/get-github-info": { @@ -322,14 +295,14 @@ } }, "node_modules/@changesets/get-release-plan": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.16.tgz", - "integrity": "sha512-OpP9QILpBp1bY2YNIKFzwigKh7Qe9KizRsZomzLe6pK8IUo8onkAAVUD8+JRKSr8R7d4+JRuQrfSSNlEwKyPYg==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.17.tgz", + "integrity": "sha512-6IwKTubNEgoOZwDontYc2x2cWXfr6IKxP3IhKeK+WjyD6y3M4Gl/jdQvBw+m/5zWILSOCAaGLu2ZF6Q+WiPniw==", "dev": true, "dependencies": { "@babel/runtime": "^7.20.1", - "@changesets/assemble-release-plan": "^5.2.3", - "@changesets/config": "^2.3.0", + "@changesets/assemble-release-plan": "^5.2.4", + "@changesets/config": "^2.3.1", "@changesets/pre": "^1.0.14", "@changesets/read": "^0.5.9", "@changesets/types": "^5.2.1", @@ -549,14 +522,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -590,9 +563,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1369,9 +1342,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -2257,9 +2230,9 @@ } }, "node_modules/@openzeppelin/upgrades-core": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.26.2.tgz", - "integrity": "sha512-TJORrgyun5qflPos/47P3j61gDw+7W+tEirSBOYRxfVL1WGjX1n8iaLrijPIqzyeS1MKguN1nckAMspQ4SKrxw==", + "version": "1.27.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.27.1.tgz", + "integrity": "sha512-6tLcu6jt0nYdJNr+LRicBgP3jp+//B+dixgB3KsvycSglCHNfmBNDf0ZQ3ZquDdLL0QQmKzIs1EBRVp6lNvPnQ==", "dev": true, "dependencies": { "cbor": "^8.0.0", @@ -2267,8 +2240,12 @@ "compare-versions": "^5.0.0", "debug": "^4.1.1", "ethereumjs-util": "^7.0.3", + "minimist": "^1.2.7", "proper-lockfile": "^4.1.1", "solidity-ast": "^0.4.15" + }, + "bin": { + "openzeppelin-upgrades-core": "dist/cli/cli.js" } }, "node_modules/@openzeppelin/upgrades-core/node_modules/ansi-styles": { @@ -2522,9 +2499,9 @@ } }, "node_modules/@truffle/abi-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.0.tgz", - "integrity": "sha512-h1wGFB28YfByAWm/uBeMCwqDlGsrcMYTumLC/sB/qYhHisi1LK6tV47FEF7zKyf6Al2CtsO28v02+wfLXbUVRg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.1.tgz", + "integrity": "sha512-ZQUY3XUxEPdqxNaoXsOqF0spTtb6f5RNlnN4MUrVsJ64sOh0FJsY7rxZiUI3khfePmNh4i2qcJrQlKT36YcWUA==", "dev": true, "dependencies": { "change-case": "3.0.2", @@ -2533,25 +2510,25 @@ } }, "node_modules/@truffle/blockchain-utils": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.7.tgz", - "integrity": "sha512-1nibqGjEHC7KAyDThEFvbm2+EO8zAHee/VjCtxkYBE3ySwP50joh0QCEBjy7K/9z+icpMoDucfxmgaKToBFUgQ==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.8.tgz", + "integrity": "sha512-ZskpYDNHkXD3ota4iU3pZz6kLth87RC+wDn66Rp2Or+DqqJCKdnmS9GDctBi1EcMPDEi0BqpkdrfBuzA9uIkGg==", "dev": true }, "node_modules/@truffle/codec": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.15.1.tgz", - "integrity": "sha512-OBANcmefxEXLApWl/uU1SOHQJixO8pDaRTybP0YMvxPhgyj7G7+wC+fUvnZdmrTJD2WJFLuoYvZbxILmycEvPg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.17.0.tgz", + "integrity": "sha512-0Z7DQNCnvW++JuvNj35v/CuJoaFSAp7/+lXWwe+Zoe++E27V+hzRI88ZYxRJa0/q1HE81epd1r0ipqc7WBotig==", "dev": true, "dependencies": { - "@truffle/abi-utils": "^1.0.0", - "@truffle/compile-common": "^0.9.5", + "@truffle/abi-utils": "^1.0.1", + "@truffle/compile-common": "^0.9.6", "big.js": "^6.0.3", "bn.js": "^5.1.3", "cbor": "^5.2.0", "debug": "^4.3.1", "lodash": "^4.17.21", - "semver": "7.3.7", + "semver": "7.5.2", "utf8": "^3.0.0", "web3-utils": "1.10.0" } @@ -2606,9 +2583,9 @@ } }, "node_modules/@truffle/codec/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2627,33 +2604,33 @@ "dev": true }, "node_modules/@truffle/compile-common": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.5.tgz", - "integrity": "sha512-qOIT7nYzQsrnpjk8LurKE6EYYvvJIk3rCHfn+xed88aG6F1l4WYtkUKl+Dcwgxgv3LH0khcQOpjqkXK5kUIJ8A==", + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.6.tgz", + "integrity": "sha512-TCcmr1E0GqMZJ2tOaCRNEllxTBJ/g7TuD6jDJpw5Gt9Bw0YO3Cmp6yPQRynRSO4xMJbHUgiEsSfRgIhswut5UA==", "dev": true, "dependencies": { - "@truffle/error": "^0.2.0", + "@truffle/error": "^0.2.1", "colors": "1.4.0" } }, "node_modules/@truffle/compile-common/node_modules/@truffle/error": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", - "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.1.tgz", + "integrity": "sha512-5Qy+z9dg9hP37WNdLnXH4b9MzemWrjTufRq7/DTKqimjyxCP/1zlL8gQEMdiSx1BBtAZz0xypkID/jb7AF/Osg==", "dev": true }, "node_modules/@truffle/contract": { - "version": "4.6.22", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.22.tgz", - "integrity": "sha512-081tM5CBBLgTQX0Fhzp0nlZHnfgojRXweV7/d6v7LHe6QGrGBmgvUy3EIbO+R3P1uaxeGVijMvB4Ok8md9IpYQ==", + "version": "4.6.26", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.26.tgz", + "integrity": "sha512-B3KM8fW9dKJCzMRD40r+u+iqQtBGFbcMr2GML31iUkjC77Wn/KlM9cCGZiuXcOquWmBlKrpD4nJCoGirPhyPTQ==", "dev": true, "dependencies": { "@ensdomains/ensjs": "^2.1.0", - "@truffle/blockchain-utils": "^0.1.7", + "@truffle/blockchain-utils": "^0.1.8", "@truffle/contract-schema": "^3.4.14", - "@truffle/debug-utils": "^6.0.50", - "@truffle/error": "^0.2.0", - "@truffle/interface-adapter": "^0.5.33", + "@truffle/debug-utils": "^6.0.54", + "@truffle/error": "^0.2.1", + "@truffle/interface-adapter": "^0.5.34", "bignumber.js": "^7.2.1", "debug": "^4.3.1", "ethers": "^4.0.32", @@ -2675,18 +2652,18 @@ } }, "node_modules/@truffle/contract/node_modules/@truffle/error": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", - "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.1.tgz", + "integrity": "sha512-5Qy+z9dg9hP37WNdLnXH4b9MzemWrjTufRq7/DTKqimjyxCP/1zlL8gQEMdiSx1BBtAZz0xypkID/jb7AF/Osg==", "dev": true }, "node_modules/@truffle/debug-utils": { - "version": "6.0.50", - "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.50.tgz", - "integrity": "sha512-OWdSoOsPW7/jvcO7ASBRzXDzXQNb7dg8UqwoBAI7j7UpdQoCAhz7JQsusSNiFN6g1qrxEpGzeh5iIMDq9WxO3w==", + "version": "6.0.54", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.54.tgz", + "integrity": "sha512-ENv5TQQv+CJrwSX9AdXXTDHVNHpPfH+yCpRSnM3Sg0dx7IeWJAjGA66/BiucNBUiAgLhV2EcvkMo+4tEPoR+YQ==", "dev": true, "dependencies": { - "@truffle/codec": "^0.15.1", + "@truffle/codec": "^0.17.0", "@trufflesuite/chromafi": "^3.0.0", "bn.js": "^5.1.3", "chalk": "^2.4.2", @@ -2707,9 +2684,9 @@ "dev": true }, "node_modules/@truffle/interface-adapter": { - "version": "0.5.33", - "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.33.tgz", - "integrity": "sha512-vbVcH2I8hX+wM0Xj9uAjpgxMHqfT+y6m26zSkOVvZ2wo9Ez1slaOJkK1/TZK+7nJitGZSXeJeB4purMDuADvGA==", + "version": "0.5.34", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.34.tgz", + "integrity": "sha512-gPxabfMi2TueE4VxnNuyeudOfvGJQ1ofVC02PFw14cnRQhzH327JikjjQbZ1bT6S7kWl9H6P3hQPFeYFMHdm1g==", "dev": true, "dependencies": { "bn.js": "^5.1.3", @@ -2917,9 +2894,9 @@ } }, "node_modules/@types/semver": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz", - "integrity": "sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, "node_modules/abbrev": { @@ -3002,9 +2979,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -3473,9 +3450,9 @@ } }, "node_modules/bigint-crypto-utils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.2.2.tgz", - "integrity": "sha512-U1RbE3aX9ayCUVcIPHuPDPKcK3SFOXf93J1UK/iHlJuQB7bhagPIX06/CLpLEsDThJ7KA4Dhrnzynl+d2weTiw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz", + "integrity": "sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==", "dev": true, "engines": { "node": ">=14.0.0" @@ -3758,9 +3735,9 @@ } }, "node_modules/cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", "dev": true, "dependencies": { "clone-response": "^1.0.2", @@ -4440,9 +4417,9 @@ } }, "node_modules/cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", "dev": true, "dependencies": { "import-fresh": "^3.2.1", @@ -4515,12 +4492,12 @@ } }, "node_modules/cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", "dev": true, "dependencies": { - "node-fetch": "^2.6.11" + "node-fetch": "^2.6.12" } }, "node_modules/cross-spawn": { @@ -5332,16 +5309,16 @@ } }, "node_modules/eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -5352,7 +5329,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "espree": "^9.6.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -5372,7 +5349,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -5607,12 +5584,12 @@ } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -6707,9 +6684,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -7401,9 +7378,9 @@ } }, "node_modules/hardhat": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.1.tgz", - "integrity": "sha512-H3Qp/UKyQGmPDDBSfMoSyH18rRnac90rsb0LNer+sKe6at6rxLe4D5j+M+1icqZQF02iLPjNRwc/PA8OPf757A==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.16.1.tgz", + "integrity": "sha512-QpBjGXFhhSYoYBGEHyoau/A63crZOP+i3GbNxzLGkL6IklzT+piN14+wGnINNCg5BLSKisQI/RAySPzaWRcx/g==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", @@ -7445,7 +7422,6 @@ "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", - "qs": "^6.7.0", "raw-body": "^2.4.1", "resolve": "1.17.0", "semver": "^6.3.0", @@ -8635,9 +8611,9 @@ "dev": true }, "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.1.tgz", + "integrity": "sha512-6Gsx8R0RucyePbWqPssR8DyfuXmLBooYN5cZFZKjHGnQuaf7pEzhtpceagJxVu4LqhYY5EYA7nko3FmeHZ1KbA==", "dev": true, "funding": { "type": "opencollective", @@ -9978,9 +9954,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -10234,17 +10210,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -10832,18 +10808,12 @@ ] }, "node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, "engines": { "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/query-string": { @@ -11183,15 +11153,6 @@ "request": "^2.34" } }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/request/node_modules/uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -11596,9 +11557,9 @@ } }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -12796,13 +12757,13 @@ } }, "node_modules/solidity-coverage": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.2.tgz", - "integrity": "sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.4.tgz", + "integrity": "sha512-xeHOfBOjdMF6hWTbt42iH4x+7j1Atmrf5OldDPMxI+i/COdExUxszOswD9qqvcBTaLGiOrrpnh9UZjSpt4rBsg==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.0.9", - "@solidity-parser/parser": "^0.14.1", + "@solidity-parser/parser": "^0.16.0", "chalk": "^2.4.2", "death": "^1.1.0", "detect-port": "^1.3.0", @@ -12829,6 +12790,15 @@ "hardhat": "^2.11.0" } }, + "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.0.tgz", + "integrity": "sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, "node_modules/solidity-coverage/node_modules/ansi-colors": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", @@ -15438,36 +15408,42 @@ } }, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" } }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/runtime": { - "version": "7.22.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz", - "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dev": true, "requires": { "regenerator-runtime": "^0.13.11" @@ -15500,13 +15476,13 @@ } }, "@changesets/apply-release-plan": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.3.tgz", - "integrity": "sha512-ECDNeoc3nfeAe1jqJb5aFQX7CqzQhD2klXRez2JDb/aVpGUbX673HgKrnrgJRuQR/9f2TtLoYIzrGB9qwD77mg==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.4.tgz", + "integrity": "sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==", "dev": true, "requires": { "@babel/runtime": "^7.20.1", - "@changesets/config": "^2.3.0", + "@changesets/config": "^2.3.1", "@changesets/get-version-range-type": "^0.3.2", "@changesets/git": "^2.0.0", "@changesets/types": "^5.2.1", @@ -15517,37 +15493,21 @@ "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", - "semver": "^5.4.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "semver": "^7.5.3" } }, "@changesets/assemble-release-plan": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.3.tgz", - "integrity": "sha512-g7EVZCmnWz3zMBAdrcKhid4hkHT+Ft1n0mLussFMcB1dE2zCuwcvGoy9ec3yOgPGF4hoMtgHaMIk3T3TBdvU9g==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.4.tgz", + "integrity": "sha512-xJkWX+1/CUaOUWTguXEbCDTyWJFECEhmdtbkjhn5GVBGxdP/JwaHBIU9sW3FR6gD07UwZ7ovpiPclQZs+j+mvg==", "dev": true, "requires": { "@babel/runtime": "^7.20.1", "@changesets/errors": "^0.1.4", - "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/get-dependents-graph": "^1.3.6", "@changesets/types": "^5.2.1", "@manypkg/get-packages": "^1.1.3", - "semver": "^5.4.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "semver": "^7.5.3" } }, "@changesets/changelog-git": { @@ -15571,19 +15531,19 @@ } }, "@changesets/cli": { - "version": "2.26.1", - "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.1.tgz", - "integrity": "sha512-XnTa+b51vt057fyAudvDKGB0Sh72xutQZNAdXkCqPBKO2zvs2yYZx5hFZj1u9cbtpwM6Sxtcr02/FQJfZOzemQ==", + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.2.tgz", + "integrity": "sha512-dnWrJTmRR8bCHikJHl9b9HW3gXACCehz4OasrXpMp7sx97ECuBGGNjJhjPhdZNCvMy9mn4BWdplI323IbqsRig==", "dev": true, "requires": { "@babel/runtime": "^7.20.1", - "@changesets/apply-release-plan": "^6.1.3", - "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/apply-release-plan": "^6.1.4", + "@changesets/assemble-release-plan": "^5.2.4", "@changesets/changelog-git": "^0.1.14", - "@changesets/config": "^2.3.0", + "@changesets/config": "^2.3.1", "@changesets/errors": "^0.1.4", - "@changesets/get-dependents-graph": "^1.3.5", - "@changesets/get-release-plan": "^3.0.16", + "@changesets/get-dependents-graph": "^1.3.6", + "@changesets/get-release-plan": "^3.0.17", "@changesets/git": "^2.0.0", "@changesets/logger": "^0.0.5", "@changesets/pre": "^1.0.14", @@ -15592,7 +15552,7 @@ "@changesets/write": "^0.2.3", "@manypkg/get-packages": "^1.1.3", "@types/is-ci": "^3.0.0", - "@types/semver": "^6.0.0", + "@types/semver": "^7.5.0", "ansi-colors": "^4.1.3", "chalk": "^2.1.0", "enquirer": "^2.3.0", @@ -15605,7 +15565,7 @@ "p-limit": "^2.2.0", "preferred-pm": "^3.0.0", "resolve-from": "^5.0.0", - "semver": "^5.4.1", + "semver": "^7.5.3", "spawndamnit": "^2.0.0", "term-size": "^2.1.0", "tty-table": "^4.1.5" @@ -15619,23 +15579,17 @@ "requires": { "p-try": "^2.0.0" } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true } } }, "@changesets/config": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.0.tgz", - "integrity": "sha512-EgP/px6mhCx8QeaMAvWtRrgyxW08k/Bx2tpGT+M84jEdX37v3VKfh4Cz1BkwrYKuMV2HZKeHOh8sHvja/HcXfQ==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.1.tgz", + "integrity": "sha512-PQXaJl82CfIXddUOppj4zWu+987GCw2M+eQcOepxN5s+kvnsZOwjEJO3DH9eVy+OP6Pg/KFEWdsECFEYTtbg6w==", "dev": true, "requires": { "@changesets/errors": "^0.1.4", - "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/get-dependents-graph": "^1.3.6", "@changesets/logger": "^0.0.5", "@changesets/types": "^5.2.1", "@manypkg/get-packages": "^1.1.3", @@ -15653,24 +15607,16 @@ } }, "@changesets/get-dependents-graph": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.5.tgz", - "integrity": "sha512-w1eEvnWlbVDIY8mWXqWuYE9oKhvIaBhzqzo4ITSJY9hgoqQ3RoBqwlcAzg11qHxv/b8ReDWnMrpjpKrW6m1ZTA==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.6.tgz", + "integrity": "sha512-Q/sLgBANmkvUm09GgRsAvEtY3p1/5OCzgBE5vX3vgb5CvW0j7CEljocx5oPXeQSNph6FXulJlXV3Re/v3K3P3Q==", "dev": true, "requires": { "@changesets/types": "^5.2.1", "@manypkg/get-packages": "^1.1.3", "chalk": "^2.1.0", "fs-extra": "^7.0.1", - "semver": "^5.4.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "semver": "^7.5.3" } }, "@changesets/get-github-info": { @@ -15684,14 +15630,14 @@ } }, "@changesets/get-release-plan": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.16.tgz", - "integrity": "sha512-OpP9QILpBp1bY2YNIKFzwigKh7Qe9KizRsZomzLe6pK8IUo8onkAAVUD8+JRKSr8R7d4+JRuQrfSSNlEwKyPYg==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.17.tgz", + "integrity": "sha512-6IwKTubNEgoOZwDontYc2x2cWXfr6IKxP3IhKeK+WjyD6y3M4Gl/jdQvBw+m/5zWILSOCAaGLu2ZF6Q+WiPniw==", "dev": true, "requires": { "@babel/runtime": "^7.20.1", - "@changesets/assemble-release-plan": "^5.2.3", - "@changesets/config": "^2.3.0", + "@changesets/assemble-release-plan": "^5.2.4", + "@changesets/config": "^2.3.1", "@changesets/pre": "^1.0.14", "@changesets/read": "^0.5.9", "@changesets/types": "^5.2.1", @@ -15892,14 +15838,14 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -15926,9 +15872,9 @@ } }, "@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", "dev": true }, "@ethereumjs/common": { @@ -16392,9 +16338,9 @@ "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -17066,9 +17012,9 @@ } }, "@openzeppelin/upgrades-core": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.26.2.tgz", - "integrity": "sha512-TJORrgyun5qflPos/47P3j61gDw+7W+tEirSBOYRxfVL1WGjX1n8iaLrijPIqzyeS1MKguN1nckAMspQ4SKrxw==", + "version": "1.27.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.27.1.tgz", + "integrity": "sha512-6tLcu6jt0nYdJNr+LRicBgP3jp+//B+dixgB3KsvycSglCHNfmBNDf0ZQ3ZquDdLL0QQmKzIs1EBRVp6lNvPnQ==", "dev": true, "requires": { "cbor": "^8.0.0", @@ -17076,6 +17022,7 @@ "compare-versions": "^5.0.0", "debug": "^4.1.1", "ethereumjs-util": "^7.0.3", + "minimist": "^1.2.7", "proper-lockfile": "^4.1.1", "solidity-ast": "^0.4.15" }, @@ -17264,9 +17211,9 @@ } }, "@truffle/abi-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.0.tgz", - "integrity": "sha512-h1wGFB28YfByAWm/uBeMCwqDlGsrcMYTumLC/sB/qYhHisi1LK6tV47FEF7zKyf6Al2CtsO28v02+wfLXbUVRg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.1.tgz", + "integrity": "sha512-ZQUY3XUxEPdqxNaoXsOqF0spTtb6f5RNlnN4MUrVsJ64sOh0FJsY7rxZiUI3khfePmNh4i2qcJrQlKT36YcWUA==", "dev": true, "requires": { "change-case": "3.0.2", @@ -17275,25 +17222,25 @@ } }, "@truffle/blockchain-utils": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.7.tgz", - "integrity": "sha512-1nibqGjEHC7KAyDThEFvbm2+EO8zAHee/VjCtxkYBE3ySwP50joh0QCEBjy7K/9z+icpMoDucfxmgaKToBFUgQ==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.8.tgz", + "integrity": "sha512-ZskpYDNHkXD3ota4iU3pZz6kLth87RC+wDn66Rp2Or+DqqJCKdnmS9GDctBi1EcMPDEi0BqpkdrfBuzA9uIkGg==", "dev": true }, "@truffle/codec": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.15.1.tgz", - "integrity": "sha512-OBANcmefxEXLApWl/uU1SOHQJixO8pDaRTybP0YMvxPhgyj7G7+wC+fUvnZdmrTJD2WJFLuoYvZbxILmycEvPg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.17.0.tgz", + "integrity": "sha512-0Z7DQNCnvW++JuvNj35v/CuJoaFSAp7/+lXWwe+Zoe++E27V+hzRI88ZYxRJa0/q1HE81epd1r0ipqc7WBotig==", "dev": true, "requires": { - "@truffle/abi-utils": "^1.0.0", - "@truffle/compile-common": "^0.9.5", + "@truffle/abi-utils": "^1.0.1", + "@truffle/compile-common": "^0.9.6", "big.js": "^6.0.3", "bn.js": "^5.1.3", "cbor": "^5.2.0", "debug": "^4.3.1", "lodash": "^4.17.21", - "semver": "7.3.7", + "semver": "7.5.2", "utf8": "^3.0.0", "web3-utils": "1.10.0" }, @@ -17336,9 +17283,9 @@ "dev": true }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -17353,35 +17300,35 @@ } }, "@truffle/compile-common": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.5.tgz", - "integrity": "sha512-qOIT7nYzQsrnpjk8LurKE6EYYvvJIk3rCHfn+xed88aG6F1l4WYtkUKl+Dcwgxgv3LH0khcQOpjqkXK5kUIJ8A==", + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.6.tgz", + "integrity": "sha512-TCcmr1E0GqMZJ2tOaCRNEllxTBJ/g7TuD6jDJpw5Gt9Bw0YO3Cmp6yPQRynRSO4xMJbHUgiEsSfRgIhswut5UA==", "dev": true, "requires": { - "@truffle/error": "^0.2.0", + "@truffle/error": "^0.2.1", "colors": "1.4.0" }, "dependencies": { "@truffle/error": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", - "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.1.tgz", + "integrity": "sha512-5Qy+z9dg9hP37WNdLnXH4b9MzemWrjTufRq7/DTKqimjyxCP/1zlL8gQEMdiSx1BBtAZz0xypkID/jb7AF/Osg==", "dev": true } } }, "@truffle/contract": { - "version": "4.6.22", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.22.tgz", - "integrity": "sha512-081tM5CBBLgTQX0Fhzp0nlZHnfgojRXweV7/d6v7LHe6QGrGBmgvUy3EIbO+R3P1uaxeGVijMvB4Ok8md9IpYQ==", + "version": "4.6.26", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.26.tgz", + "integrity": "sha512-B3KM8fW9dKJCzMRD40r+u+iqQtBGFbcMr2GML31iUkjC77Wn/KlM9cCGZiuXcOquWmBlKrpD4nJCoGirPhyPTQ==", "dev": true, "requires": { "@ensdomains/ensjs": "^2.1.0", - "@truffle/blockchain-utils": "^0.1.7", + "@truffle/blockchain-utils": "^0.1.8", "@truffle/contract-schema": "^3.4.14", - "@truffle/debug-utils": "^6.0.50", - "@truffle/error": "^0.2.0", - "@truffle/interface-adapter": "^0.5.33", + "@truffle/debug-utils": "^6.0.54", + "@truffle/error": "^0.2.1", + "@truffle/interface-adapter": "^0.5.34", "bignumber.js": "^7.2.1", "debug": "^4.3.1", "ethers": "^4.0.32", @@ -17393,9 +17340,9 @@ }, "dependencies": { "@truffle/error": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", - "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.1.tgz", + "integrity": "sha512-5Qy+z9dg9hP37WNdLnXH4b9MzemWrjTufRq7/DTKqimjyxCP/1zlL8gQEMdiSx1BBtAZz0xypkID/jb7AF/Osg==", "dev": true } } @@ -17411,12 +17358,12 @@ } }, "@truffle/debug-utils": { - "version": "6.0.50", - "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.50.tgz", - "integrity": "sha512-OWdSoOsPW7/jvcO7ASBRzXDzXQNb7dg8UqwoBAI7j7UpdQoCAhz7JQsusSNiFN6g1qrxEpGzeh5iIMDq9WxO3w==", + "version": "6.0.54", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.54.tgz", + "integrity": "sha512-ENv5TQQv+CJrwSX9AdXXTDHVNHpPfH+yCpRSnM3Sg0dx7IeWJAjGA66/BiucNBUiAgLhV2EcvkMo+4tEPoR+YQ==", "dev": true, "requires": { - "@truffle/codec": "^0.15.1", + "@truffle/codec": "^0.17.0", "@trufflesuite/chromafi": "^3.0.0", "bn.js": "^5.1.3", "chalk": "^2.4.2", @@ -17439,9 +17386,9 @@ "dev": true }, "@truffle/interface-adapter": { - "version": "0.5.33", - "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.33.tgz", - "integrity": "sha512-vbVcH2I8hX+wM0Xj9uAjpgxMHqfT+y6m26zSkOVvZ2wo9Ez1slaOJkK1/TZK+7nJitGZSXeJeB4purMDuADvGA==", + "version": "0.5.34", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.34.tgz", + "integrity": "sha512-gPxabfMi2TueE4VxnNuyeudOfvGJQ1ofVC02PFw14cnRQhzH327JikjjQbZ1bT6S7kWl9H6P3hQPFeYFMHdm1g==", "dev": true, "requires": { "bn.js": "^5.1.3", @@ -17651,9 +17598,9 @@ } }, "@types/semver": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz", - "integrity": "sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, "abbrev": { @@ -17715,9 +17662,9 @@ } }, "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true }, "acorn-jsx": { @@ -18064,9 +18011,9 @@ "dev": true }, "bigint-crypto-utils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.2.2.tgz", - "integrity": "sha512-U1RbE3aX9ayCUVcIPHuPDPKcK3SFOXf93J1UK/iHlJuQB7bhagPIX06/CLpLEsDThJ7KA4Dhrnzynl+d2weTiw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz", + "integrity": "sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==", "dev": true }, "bignumber.js": { @@ -18302,9 +18249,9 @@ "dev": true }, "cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", "dev": true, "requires": { "clone-response": "^1.0.2", @@ -18845,9 +18792,9 @@ } }, "cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", "dev": true, "requires": { "import-fresh": "^3.2.1", @@ -18907,12 +18854,12 @@ } }, "cross-fetch": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", - "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", "dev": true, "requires": { - "node-fetch": "^2.6.11" + "node-fetch": "^2.6.12" } }, "cross-spawn": { @@ -19538,16 +19485,16 @@ } }, "eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -19558,7 +19505,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "espree": "^9.6.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -19578,7 +19525,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -19732,12 +19679,12 @@ "dev": true }, "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", "dev": true, "requires": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } @@ -20668,9 +20615,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -21205,9 +21152,9 @@ "dev": true }, "hardhat": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.1.tgz", - "integrity": "sha512-H3Qp/UKyQGmPDDBSfMoSyH18rRnac90rsb0LNer+sKe6at6rxLe4D5j+M+1icqZQF02iLPjNRwc/PA8OPf757A==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.16.1.tgz", + "integrity": "sha512-QpBjGXFhhSYoYBGEHyoau/A63crZOP+i3GbNxzLGkL6IklzT+piN14+wGnINNCg5BLSKisQI/RAySPzaWRcx/g==", "dev": true, "requires": { "@ethersproject/abi": "^5.1.2", @@ -21249,7 +21196,6 @@ "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", - "qs": "^6.7.0", "raw-body": "^2.4.1", "resolve": "1.17.0", "semver": "^6.3.0", @@ -22126,9 +22072,9 @@ "dev": true }, "js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.1.tgz", + "integrity": "sha512-6Gsx8R0RucyePbWqPssR8DyfuXmLBooYN5cZFZKjHGnQuaf7pEzhtpceagJxVu4LqhYY5EYA7nko3FmeHZ1KbA==", "dev": true }, "js-sha3": { @@ -23190,9 +23136,9 @@ } }, "node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dev": true, "requires": { "whatwg-url": "^5.0.0" @@ -23376,17 +23322,17 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" } }, "os-locale": { @@ -23825,13 +23771,10 @@ "dev": true }, "qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true }, "query-string": { "version": "5.1.1", @@ -24064,12 +24007,6 @@ "uuid": "^3.3.2" }, "dependencies": { - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -24382,9 +24319,9 @@ } }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -25290,13 +25227,13 @@ "optional": true }, "solidity-coverage": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.2.tgz", - "integrity": "sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.4.tgz", + "integrity": "sha512-xeHOfBOjdMF6hWTbt42iH4x+7j1Atmrf5OldDPMxI+i/COdExUxszOswD9qqvcBTaLGiOrrpnh9UZjSpt4rBsg==", "dev": true, "requires": { "@ethersproject/abi": "^5.0.9", - "@solidity-parser/parser": "^0.14.1", + "@solidity-parser/parser": "^0.16.0", "chalk": "^2.4.2", "death": "^1.1.0", "detect-port": "^1.3.0", @@ -25317,6 +25254,15 @@ "web3-utils": "^1.3.6" }, "dependencies": { + "@solidity-parser/parser": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.0.tgz", + "integrity": "sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, "ansi-colors": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", From 6bf68a41d19f3d6e364d8c207cb7d1a9a8e542e1 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 6 Jul 2023 05:00:34 -0300 Subject: [PATCH 15/16] Remove "available since" comments (#4424) Co-authored-by: Hadrien Croubois --- contracts/access/AccessControl.sol | 4 - .../access/AccessControlDefaultAdminRules.sol | 2 - contracts/access/IAccessControl.sol | 2 - .../IAccessControlDefaultAdminRules.sol | 2 - contracts/governance/Governor.sol | 2 - contracts/governance/IGovernor.sol | 2 - contracts/governance/TimelockController.sol | 2 - .../GovernorCompatibilityBravo.sol | 2 - .../IGovernorCompatibilityBravo.sol | 2 - .../extensions/GovernorCountingSimple.sol | 2 - .../extensions/GovernorPreventLateQuorum.sol | 2 - .../extensions/GovernorSettings.sol | 2 - .../extensions/GovernorTimelockCompound.sol | 2 - .../extensions/GovernorTimelockControl.sol | 2 - .../governance/extensions/GovernorVotes.sol | 2 - .../GovernorVotesQuorumFraction.sol | 2 - .../extensions/IGovernorTimelock.sol | 2 - contracts/governance/utils/IVotes.sol | 2 - contracts/governance/utils/Votes.sol | 2 - contracts/interfaces/IERC1271.sol | 2 - contracts/interfaces/IERC1967.sol | 2 - contracts/interfaces/IERC2309.sol | 2 - contracts/interfaces/IERC2981.sol | 2 - .../interfaces/IERC3156FlashBorrower.sol | 2 - contracts/interfaces/IERC3156FlashLender.sol | 2 - contracts/interfaces/IERC4626.sol | 2 - contracts/interfaces/IERC5313.sol | 2 - contracts/proxy/Clones.sol | 2 - contracts/proxy/ERC1967/ERC1967Utils.sol | 2 - contracts/proxy/beacon/BeaconProxy.sol | 2 - contracts/proxy/utils/UUPSUpgradeable.sol | 2 - contracts/token/ERC1155/ERC1155.sol | 2 - contracts/token/ERC1155/IERC1155.sol | 2 - contracts/token/ERC1155/IERC1155Receiver.sol | 3 +- .../ERC1155/extensions/ERC1155Burnable.sol | 2 - .../ERC1155/extensions/ERC1155Pausable.sol | 2 - .../ERC1155/extensions/ERC1155URIStorage.sol | 2 - .../extensions/IERC1155MetadataURI.sol | 2 - .../token/ERC1155/utils/ERC1155Holder.sol | 4 +- .../token/ERC1155/utils/ERC1155Receiver.sol | 4 +- .../token/ERC20/extensions/ERC20FlashMint.sol | 2 - .../token/ERC20/extensions/ERC20Permit.sol | 2 - .../token/ERC20/extensions/ERC20Votes.sol | 2 - .../token/ERC20/extensions/ERC20Wrapper.sol | 2 - contracts/token/ERC20/extensions/ERC4626.sol | 2 - .../token/ERC20/extensions/IERC20Metadata.sol | 2 - .../ERC721/extensions/ERC721Consecutive.sol | 2 - .../token/ERC721/extensions/ERC721Royalty.sol | 2 - .../token/ERC721/extensions/ERC721Votes.sol | 2 - .../token/ERC721/extensions/ERC721Wrapper.sol | 2 - contracts/token/common/ERC2981.sol | 2 - contracts/utils/Address.sol | 22 --- contracts/utils/Base64.sol | 2 - contracts/utils/Multicall.sol | 2 - contracts/utils/StorageSlot.sol | 3 - contracts/utils/cryptography/ECDSA.sol | 8 -- contracts/utils/cryptography/EIP712.sol | 8 -- contracts/utils/cryptography/MerkleProof.sol | 14 -- .../utils/cryptography/SignatureChecker.sol | 2 - .../utils/introspection/ERC165Checker.sol | 2 - contracts/utils/math/Math.sol | 10 -- contracts/utils/math/SafeCast.sol | 128 ------------------ contracts/utils/structs/Checkpoints.sol | 2 - contracts/utils/structs/DoubleEndedQueue.sol | 2 - scripts/generate/templates/Checkpoints.js | 2 - scripts/generate/templates/SafeCast.js | 65 --------- scripts/generate/templates/StorageSlot.js | 23 +--- scripts/upgradeable/upgradeable.patch | 29 ++-- 68 files changed, 26 insertions(+), 407 deletions(-) diff --git a/contracts/access/AccessControl.sol b/contracts/access/AccessControl.sol index 8465fefbd..ec30e81e7 100644 --- a/contracts/access/AccessControl.sol +++ b/contracts/access/AccessControl.sol @@ -64,8 +64,6 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 { * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ - * - * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); @@ -91,8 +89,6 @@ abstract contract AccessControl is Context, IAccessControl, ERC165 { * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. - * - * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); diff --git a/contracts/access/AccessControlDefaultAdminRules.sol b/contracts/access/AccessControlDefaultAdminRules.sol index ebc40a5bf..4572a328d 100644 --- a/contracts/access/AccessControlDefaultAdminRules.sol +++ b/contracts/access/AccessControlDefaultAdminRules.sol @@ -35,8 +35,6 @@ import {IERC5313} from "../interfaces/IERC5313.sol"; * ) {} * } * ``` - * - * _Available since v4.9._ */ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl { // pending admin pair read/written together frequently diff --git a/contracts/access/IAccessControl.sol b/contracts/access/IAccessControl.sol index 9abc2b735..38facbfb1 100644 --- a/contracts/access/IAccessControl.sol +++ b/contracts/access/IAccessControl.sol @@ -24,8 +24,6 @@ interface IAccessControl { * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. - * - * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); diff --git a/contracts/access/IAccessControlDefaultAdminRules.sol b/contracts/access/IAccessControlDefaultAdminRules.sol index 5e61f965d..a1afb3d22 100644 --- a/contracts/access/IAccessControlDefaultAdminRules.sol +++ b/contracts/access/IAccessControlDefaultAdminRules.sol @@ -7,8 +7,6 @@ import {IAccessControl} from "./IAccessControl.sol"; /** * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection. - * - * _Available since v4.9._ */ interface IAccessControlDefaultAdminRules is IAccessControl { /** diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index a66a1a6bf..94f29e95f 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -23,8 +23,6 @@ import {IGovernor, IERC6372} from "./IGovernor.sol"; * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote} * - A voting module must implement {_getVotes} * - Additionally, {votingPeriod} must also be implemented - * - * _Available since v4.3._ */ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC721Receiver, IERC1155Receiver { using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index af4698226..b954ed205 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -8,8 +8,6 @@ import {IERC6372} from "../interfaces/IERC6372.sol"; /** * @dev Interface of the {Governor} core. - * - * _Available since v4.3._ */ abstract contract IGovernor is IERC165, IERC6372 { enum ProposalState { diff --git a/contracts/governance/TimelockController.sol b/contracts/governance/TimelockController.sol index ff8d45595..2cf954d12 100644 --- a/contracts/governance/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -21,8 +21,6 @@ import {Address} from "../utils/Address.sol"; * is in charge of proposing (resp executing) operations. A common use case is * to position this {TimelockController} as the owner of a smart contract, with * a multisig or a DAO as the sole proposer. - * - * _Available since v3.3._ */ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 445f71be0..40284c578 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -15,8 +15,6 @@ import {IGovernorCompatibilityBravo} from "./IGovernorCompatibilityBravo.sol"; * through inheritance. It does not include token bindings, nor does it include any variable upgrade patterns. * * NOTE: When using this module, you may need to enable the Solidity optimizer to avoid hitting the contract size limit. - * - * _Available since v4.3._ */ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorCompatibilityBravo, Governor { enum VoteType { diff --git a/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol b/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol index 4bd593077..5476edf4f 100644 --- a/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol @@ -7,8 +7,6 @@ import {IGovernor} from "../IGovernor.sol"; /** * @dev Interface extension that adds missing functions to the {Governor} core to provide `GovernorBravo` compatibility. - * - * _Available since v4.3._ */ abstract contract IGovernorCompatibilityBravo is IGovernor { /** diff --git a/contracts/governance/extensions/GovernorCountingSimple.sol b/contracts/governance/extensions/GovernorCountingSimple.sol index 8934995de..6496c3acc 100644 --- a/contracts/governance/extensions/GovernorCountingSimple.sol +++ b/contracts/governance/extensions/GovernorCountingSimple.sol @@ -7,8 +7,6 @@ import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} for simple, 3 options, vote counting. - * - * _Available since v4.3._ */ abstract contract GovernorCountingSimple is Governor { /** diff --git a/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/contracts/governance/extensions/GovernorPreventLateQuorum.sol index 8687b6fd1..89c02fce6 100644 --- a/contracts/governance/extensions/GovernorPreventLateQuorum.sol +++ b/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -14,8 +14,6 @@ import {Math} from "../../utils/math/Math.sol"; * If a vote causes quorum to be reached, the proposal's voting period may be extended so that it does not end before at * least a specified time has passed (the "vote extension" parameter). This parameter can be set through a governance * proposal. - * - * _Available since v4.5._ */ abstract contract GovernorPreventLateQuorum is Governor { uint48 private _voteExtension; diff --git a/contracts/governance/extensions/GovernorSettings.sol b/contracts/governance/extensions/GovernorSettings.sol index 5d98fbf34..834555654 100644 --- a/contracts/governance/extensions/GovernorSettings.sol +++ b/contracts/governance/extensions/GovernorSettings.sol @@ -7,8 +7,6 @@ import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} for settings updatable through governance. - * - * _Available since v4.4._ */ abstract contract GovernorSettings is Governor { // amount of token diff --git a/contracts/governance/extensions/GovernorTimelockCompound.sol b/contracts/governance/extensions/GovernorTimelockCompound.sol index 935600d56..4b609723d 100644 --- a/contracts/governance/extensions/GovernorTimelockCompound.sol +++ b/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -19,8 +19,6 @@ import {Address} from "../../utils/Address.sol"; * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be * inaccessible. - * - * _Available since v4.3._ */ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { ICompoundTimelock private _timelock; diff --git a/contracts/governance/extensions/GovernorTimelockControl.sol b/contracts/governance/extensions/GovernorTimelockControl.sol index fefe31555..111569408 100644 --- a/contracts/governance/extensions/GovernorTimelockControl.sol +++ b/contracts/governance/extensions/GovernorTimelockControl.sol @@ -21,8 +21,6 @@ import {IERC165} from "../../interfaces/IERC165.sol"; * grants them powers that they must be trusted or known not to use: 1) {onlyGovernance} functions like {relay} are * available to them through the timelock, and 2) approved governance proposals can be blocked by them, effectively * executing a Denial of Service attack. This risk will be mitigated in a future release. - * - * _Available since v4.3._ */ abstract contract GovernorTimelockControl is IGovernorTimelock, Governor { TimelockController private _timelock; diff --git a/contracts/governance/extensions/GovernorVotes.sol b/contracts/governance/extensions/GovernorVotes.sol index bb14d7fde..eea43290e 100644 --- a/contracts/governance/extensions/GovernorVotes.sol +++ b/contracts/governance/extensions/GovernorVotes.sol @@ -10,8 +10,6 @@ import {SafeCast} from "../../utils/math/SafeCast.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} token. - * - * _Available since v4.3._ */ abstract contract GovernorVotes is Governor { IERC5805 public immutable token; diff --git a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol index 5d7976b14..7782130fa 100644 --- a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol +++ b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -10,8 +10,6 @@ import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a * fraction of the total supply. - * - * _Available since v4.3._ */ abstract contract GovernorVotesQuorumFraction is GovernorVotes { using Checkpoints for Checkpoints.Trace224; diff --git a/contracts/governance/extensions/IGovernorTimelock.sol b/contracts/governance/extensions/IGovernorTimelock.sol index 00254853a..7d9c3c554 100644 --- a/contracts/governance/extensions/IGovernorTimelock.sol +++ b/contracts/governance/extensions/IGovernorTimelock.sol @@ -7,8 +7,6 @@ import {IGovernor} from "../IGovernor.sol"; /** * @dev Extension of the {IGovernor} for timelock supporting modules. - * - * _Available since v4.3._ */ abstract contract IGovernorTimelock is IGovernor { /** diff --git a/contracts/governance/utils/IVotes.sol b/contracts/governance/utils/IVotes.sol index ee17721ff..c664d1255 100644 --- a/contracts/governance/utils/IVotes.sol +++ b/contracts/governance/utils/IVotes.sol @@ -4,8 +4,6 @@ pragma solidity ^0.8.19; /** * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. - * - * _Available since v4.5._ */ interface IVotes { /** diff --git a/contracts/governance/utils/Votes.sol b/contracts/governance/utils/Votes.sol index 988255189..1c0bb3289 100644 --- a/contracts/governance/utils/Votes.sol +++ b/contracts/governance/utils/Votes.sol @@ -27,8 +27,6 @@ import {ECDSA} from "../../utils/cryptography/ECDSA.sol"; * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the * previous example, it would be included in {ERC721-_beforeTokenTransfer}). - * - * _Available since v4.5._ */ abstract contract Votes is Context, EIP712, Nonces, IERC5805 { using Checkpoints for Checkpoints.Trace224; diff --git a/contracts/interfaces/IERC1271.sol b/contracts/interfaces/IERC1271.sol index e7fca3079..1523f988e 100644 --- a/contracts/interfaces/IERC1271.sol +++ b/contracts/interfaces/IERC1271.sol @@ -6,8 +6,6 @@ pragma solidity ^0.8.19; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. - * - * _Available since v4.1._ */ interface IERC1271 { /** diff --git a/contracts/interfaces/IERC1967.sol b/contracts/interfaces/IERC1967.sol index 190d86b2c..a57f767f1 100644 --- a/contracts/interfaces/IERC1967.sol +++ b/contracts/interfaces/IERC1967.sol @@ -5,8 +5,6 @@ pragma solidity ^0.8.19; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. - * - * _Available since v4.8.3._ */ interface IERC1967 { /** diff --git a/contracts/interfaces/IERC2309.sol b/contracts/interfaces/IERC2309.sol index 9d8886994..cd967e41b 100644 --- a/contracts/interfaces/IERC2309.sol +++ b/contracts/interfaces/IERC2309.sol @@ -5,8 +5,6 @@ pragma solidity ^0.8.19; /** * @dev ERC-2309: ERC-721 Consecutive Transfer Extension. - * - * _Available since v4.8._ */ interface IERC2309 { /** diff --git a/contracts/interfaces/IERC2981.sol b/contracts/interfaces/IERC2981.sol index ba0f98c99..18cfa7135 100644 --- a/contracts/interfaces/IERC2981.sol +++ b/contracts/interfaces/IERC2981.sol @@ -10,8 +10,6 @@ import {IERC165} from "../utils/introspection/IERC165.sol"; * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. - * - * _Available since v4.5._ */ interface IERC2981 is IERC165 { /** diff --git a/contracts/interfaces/IERC3156FlashBorrower.sol b/contracts/interfaces/IERC3156FlashBorrower.sol index 3f216194b..5c0b88de4 100644 --- a/contracts/interfaces/IERC3156FlashBorrower.sol +++ b/contracts/interfaces/IERC3156FlashBorrower.sol @@ -6,8 +6,6 @@ pragma solidity ^0.8.19; /** * @dev Interface of the ERC3156 FlashBorrower, as defined in * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. - * - * _Available since v4.1._ */ interface IERC3156FlashBorrower { /** diff --git a/contracts/interfaces/IERC3156FlashLender.sol b/contracts/interfaces/IERC3156FlashLender.sol index e5dd9c523..b52428a06 100644 --- a/contracts/interfaces/IERC3156FlashLender.sol +++ b/contracts/interfaces/IERC3156FlashLender.sol @@ -8,8 +8,6 @@ import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; /** * @dev Interface of the ERC3156 FlashLender, as defined in * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. - * - * _Available since v4.1._ */ interface IERC3156FlashLender { /** diff --git a/contracts/interfaces/IERC4626.sol b/contracts/interfaces/IERC4626.sol index 27735f6b9..8854b0022 100644 --- a/contracts/interfaces/IERC4626.sol +++ b/contracts/interfaces/IERC4626.sol @@ -9,8 +9,6 @@ import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. - * - * _Available since v4.7._ */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); diff --git a/contracts/interfaces/IERC5313.sol b/contracts/interfaces/IERC5313.sol index 1d17080a1..1150c322c 100644 --- a/contracts/interfaces/IERC5313.sol +++ b/contracts/interfaces/IERC5313.sol @@ -7,8 +7,6 @@ pragma solidity ^0.8.19; * @dev Interface for the Light Contract Ownership Standard. * * A standardized minimal interface required to identify an account that controls a contract - * - * _Available since v4.9._ */ interface IERC5313 { /** diff --git a/contracts/proxy/Clones.sol b/contracts/proxy/Clones.sol index d859d5645..fea1db13a 100644 --- a/contracts/proxy/Clones.sol +++ b/contracts/proxy/Clones.sol @@ -13,8 +13,6 @@ pragma solidity ^0.8.19; * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. - * - * _Available since v3.4._ */ library Clones { /** diff --git a/contracts/proxy/ERC1967/ERC1967Utils.sol b/contracts/proxy/ERC1967/ERC1967Utils.sol index 843fa6584..f7caaa684 100644 --- a/contracts/proxy/ERC1967/ERC1967Utils.sol +++ b/contracts/proxy/ERC1967/ERC1967Utils.sol @@ -10,8 +10,6 @@ import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. - * - * _Available since v4.1._ */ library ERC1967Utils { // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. diff --git a/contracts/proxy/beacon/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol index 57883b692..94e697ca4 100644 --- a/contracts/proxy/beacon/BeaconProxy.sol +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -12,8 +12,6 @@ import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; * * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't * conflict with the storage layout of the implementation behind the proxy. - * - * _Available since v3.4._ */ contract BeaconProxy is Proxy { /** diff --git a/contracts/proxy/utils/UUPSUpgradeable.sol b/contracts/proxy/utils/UUPSUpgradeable.sol index 7d1515bbb..f4045aa6f 100644 --- a/contracts/proxy/utils/UUPSUpgradeable.sol +++ b/contracts/proxy/utils/UUPSUpgradeable.sol @@ -15,8 +15,6 @@ import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. - * - * _Available since v4.1._ */ abstract contract UUPSUpgradeable is IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment diff --git a/contracts/token/ERC1155/ERC1155.sol b/contracts/token/ERC1155/ERC1155.sol index a9028f323..7b1c9cfff 100644 --- a/contracts/token/ERC1155/ERC1155.sol +++ b/contracts/token/ERC1155/ERC1155.sol @@ -15,8 +15,6 @@ import {IERC1155Errors} from "../../interfaces/draft-IERC6093.sol"; * @dev Implementation of the basic standard multi-token. * See https://eips.ethereum.org/EIPS/eip-1155 * Originally based on code by Enjin: https://github.com/enjin/erc-1155 - * - * _Available since v3.1._ */ abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors { using Arrays for uint256[]; diff --git a/contracts/token/ERC1155/IERC1155.sol b/contracts/token/ERC1155/IERC1155.sol index 1b0b0ae9d..19b626c9a 100644 --- a/contracts/token/ERC1155/IERC1155.sol +++ b/contracts/token/ERC1155/IERC1155.sol @@ -8,8 +8,6 @@ import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. - * - * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** diff --git a/contracts/token/ERC1155/IERC1155Receiver.sol b/contracts/token/ERC1155/IERC1155Receiver.sol index 04ef783f1..ce3265246 100644 --- a/contracts/token/ERC1155/IERC1155Receiver.sol +++ b/contracts/token/ERC1155/IERC1155Receiver.sol @@ -6,7 +6,8 @@ pragma solidity ^0.8.19; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** - * @dev _Available since v3.1._ + * @dev Interface that must be implemented by smart contracts in order to receive + * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** diff --git a/contracts/token/ERC1155/extensions/ERC1155Burnable.sol b/contracts/token/ERC1155/extensions/ERC1155Burnable.sol index 5ebfcf6c4..3696d1bbe 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Burnable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Burnable.sol @@ -8,8 +8,6 @@ import {ERC1155} from "../ERC1155.sol"; /** * @dev Extension of {ERC1155} that allows token holders to destroy both their * own tokens and those that they have been approved to use. - * - * _Available since v3.1._ */ abstract contract ERC1155Burnable is ERC1155 { function burn(address account, uint256 id, uint256 value) public virtual { diff --git a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol index 960cd3b6e..a51f21599 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -18,8 +18,6 @@ import {Pausable} from "../../../security/Pausable.sol"; * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will * make the contract pause mechanism of the contract unreachable, and thus unusable. - * - * _Available since v3.1._ */ abstract contract ERC1155Pausable is ERC1155, Pausable { /** diff --git a/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol b/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol index 303b452b8..2e502fd35 100644 --- a/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol +++ b/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol @@ -9,8 +9,6 @@ import {ERC1155} from "../ERC1155.sol"; /** * @dev ERC1155 token with storage based token URI management. * Inspired by the ERC721URIStorage extension - * - * _Available since v4.6._ */ abstract contract ERC1155URIStorage is ERC1155 { using Strings for uint256; diff --git a/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol b/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol index 88462ef87..d0391d371 100644 --- a/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol +++ b/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol @@ -8,8 +8,6 @@ import {IERC1155} from "../IERC1155.sol"; /** * @dev Interface of the optional ERC1155MetadataExtension interface, as defined * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. - * - * _Available since v3.1._ */ interface IERC1155MetadataURI is IERC1155 { /** diff --git a/contracts/token/ERC1155/utils/ERC1155Holder.sol b/contracts/token/ERC1155/utils/ERC1155Holder.sol index 87c42b02f..e288f8692 100644 --- a/contracts/token/ERC1155/utils/ERC1155Holder.sol +++ b/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -6,12 +6,10 @@ pragma solidity ^0.8.19; import {ERC1155Receiver} from "./ERC1155Receiver.sol"; /** - * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. + * @dev Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. - * - * @dev _Available since v3.1._ */ abstract contract ERC1155Holder is ERC1155Receiver { function onERC1155Received( diff --git a/contracts/token/ERC1155/utils/ERC1155Receiver.sol b/contracts/token/ERC1155/utils/ERC1155Receiver.sol index cf948ced7..02f922cf8 100644 --- a/contracts/token/ERC1155/utils/ERC1155Receiver.sol +++ b/contracts/token/ERC1155/utils/ERC1155Receiver.sol @@ -7,7 +7,9 @@ import {IERC1155Receiver} from "../IERC1155Receiver.sol"; import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; /** - * @dev _Available since v3.1._ + * @dev Basic contract implementing the ERC-165 interface for {IERC1155Receiver}. + * + * NOTE: This contract does not suffice to receive tokens. See {ERC1155Holder}. */ abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { /** diff --git a/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/contracts/token/ERC20/extensions/ERC20FlashMint.sol index 0583af5df..5d3e11f76 100644 --- a/contracts/token/ERC20/extensions/ERC20FlashMint.sol +++ b/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -17,8 +17,6 @@ import {ERC20} from "../ERC20.sol"; * NOTE: When this extension is used along with the {ERC20Capped} or {ERC20Votes} extensions, * {maxFlashLoan} will not correctly reflect the maximum that can be flash minted. We recommend * overriding {maxFlashLoan} so that it correctly reflects the supply cap. - * - * _Available since v4.1._ */ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); diff --git a/contracts/token/ERC20/extensions/ERC20Permit.sol b/contracts/token/ERC20/extensions/ERC20Permit.sol index 8778f4baf..c83c7dae7 100644 --- a/contracts/token/ERC20/extensions/ERC20Permit.sol +++ b/contracts/token/ERC20/extensions/ERC20Permit.sol @@ -16,8 +16,6 @@ import {Nonces} from "../../../utils/Nonces.sol"; * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. - * - * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces { // solhint-disable-next-line var-name-mixedcase diff --git a/contracts/token/ERC20/extensions/ERC20Votes.sol b/contracts/token/ERC20/extensions/ERC20Votes.sol index c27115eaa..e0d675b2a 100644 --- a/contracts/token/ERC20/extensions/ERC20Votes.sol +++ b/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -20,8 +20,6 @@ import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; * * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. - * - * _Available since v4.2._ */ abstract contract ERC20Votes is ERC20, Votes { /** diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol index c9e33d00a..fb5f314d7 100644 --- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol +++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -12,8 +12,6 @@ import {SafeERC20} from "../utils/SafeERC20.sol"; * Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC20Votes} will allow the * wrapping of an existing "basic" ERC20 into a governance token. - * - * _Available since v4.2._ */ abstract contract ERC20Wrapper is ERC20 { IERC20 private immutable _underlying; diff --git a/contracts/token/ERC20/extensions/ERC4626.sol b/contracts/token/ERC20/extensions/ERC4626.sol index cb5e03da8..11f1cd593 100644 --- a/contracts/token/ERC20/extensions/ERC4626.sol +++ b/contracts/token/ERC20/extensions/ERC4626.sol @@ -44,8 +44,6 @@ import {Math} from "../../../utils/math/Math.sol"; * * To learn more, check out our xref:ROOT:erc4626.adoc[ERC-4626 guide]. * ==== - * - * _Available since v4.7._ */ abstract contract ERC4626 is ERC20, IERC4626 { using Math for uint256; diff --git a/contracts/token/ERC20/extensions/IERC20Metadata.sol b/contracts/token/ERC20/extensions/IERC20Metadata.sol index bdfe81145..d79bbaa39 100644 --- a/contracts/token/ERC20/extensions/IERC20Metadata.sol +++ b/contracts/token/ERC20/extensions/IERC20Metadata.sol @@ -7,8 +7,6 @@ import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. - * - * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** diff --git a/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/contracts/token/ERC721/extensions/ERC721Consecutive.sol index e25edfcd9..7c37e0764 100644 --- a/contracts/token/ERC721/extensions/ERC721Consecutive.sol +++ b/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -26,8 +26,6 @@ import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; * IMPORTANT: When overriding {_afterTokenTransfer}, be careful about call ordering. {ownerOf} may return invalid * values during the {_afterTokenTransfer} execution if the super call is not called first. To be safe, execute the * super call before your custom logic. - * - * _Available since v4.8._ */ abstract contract ERC721Consecutive is IERC2309, ERC721 { using BitMaps for BitMaps.BitMap; diff --git a/contracts/token/ERC721/extensions/ERC721Royalty.sol b/contracts/token/ERC721/extensions/ERC721Royalty.sol index b4518dc24..eb128ac58 100644 --- a/contracts/token/ERC721/extensions/ERC721Royalty.sol +++ b/contracts/token/ERC721/extensions/ERC721Royalty.sol @@ -17,8 +17,6 @@ import {ERC165} from "../../../utils/introspection/ERC165.sol"; * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. - * - * _Available since v4.5._ */ abstract contract ERC721Royalty is ERC2981, ERC721 { /** diff --git a/contracts/token/ERC721/extensions/ERC721Votes.sol b/contracts/token/ERC721/extensions/ERC721Votes.sol index 1e694e4c7..0838010eb 100644 --- a/contracts/token/ERC721/extensions/ERC721Votes.sol +++ b/contracts/token/ERC721/extensions/ERC721Votes.sol @@ -13,8 +13,6 @@ import {Votes} from "../../../governance/utils/Votes.sol"; * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of * the votes in governance decisions, or they can delegate to themselves to be their own representative. - * - * _Available since v4.5._ */ abstract contract ERC721Votes is ERC721, Votes { /** diff --git a/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/contracts/token/ERC721/extensions/ERC721Wrapper.sol index b8c396c3e..f204c1079 100644 --- a/contracts/token/ERC721/extensions/ERC721Wrapper.sol +++ b/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -12,8 +12,6 @@ import {IERC721Receiver} from "../IERC721Receiver.sol"; * Users can deposit and withdraw an "underlying token" and receive a "wrapped token" with a matching tokenId. This is useful * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC721Votes} will allow the * wrapping of an existing "basic" ERC721 into a governance token. - * - * _Available since v4.9.0_ */ abstract contract ERC721Wrapper is ERC721, IERC721Receiver { IERC721 private immutable _underlying; diff --git a/contracts/token/common/ERC2981.sol b/contracts/token/common/ERC2981.sol index b9183e34e..e683b41c5 100644 --- a/contracts/token/common/ERC2981.sol +++ b/contracts/token/common/ERC2981.sol @@ -18,8 +18,6 @@ import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. - * - * _Available since v4.5._ */ abstract contract ERC2981 is IERC2981, ERC165 { struct RoyaltyInfo { diff --git a/contracts/utils/Address.sol b/contracts/utils/Address.sol index 859332b39..3f5d0a55b 100644 --- a/contracts/utils/Address.sol +++ b/contracts/utils/Address.sol @@ -64,8 +64,6 @@ library Address { * * - `target` must be a contract. * - calling `target` with `data` must not revert. - * - * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, defaultRevert); @@ -78,8 +76,6 @@ library Address { * Requirements: * * - `customRevert` must be a reverting function. - * - * _Available since v5.0._ */ function functionCall( address target, @@ -97,8 +93,6 @@ library Address { * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. - * - * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, defaultRevert); @@ -111,8 +105,6 @@ library Address { * Requirements: * * - `customRevert` must be a reverting function. - * - * _Available since v5.0._ */ function functionCallWithValue( address target, @@ -130,8 +122,6 @@ library Address { /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. - * - * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, defaultRevert); @@ -140,8 +130,6 @@ library Address { /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. - * - * _Available since v3.3._ */ function functionStaticCall( address target, @@ -155,8 +143,6 @@ library Address { /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. - * - * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, defaultRevert); @@ -165,8 +151,6 @@ library Address { /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. - * - * _Available since v3.4._ */ function functionDelegateCall( address target, @@ -180,8 +164,6 @@ library Address { /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided `customRevert`) in case of unsuccessful call or if target was not a contract. - * - * _Available since v5.0._ */ function verifyCallResultFromTarget( address target, @@ -206,8 +188,6 @@ library Address { /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or with a default revert error. - * - * _Available since v5.0._ */ function verifyCallResult(bool success, bytes memory returndata) internal view returns (bytes memory) { return verifyCallResult(success, returndata, defaultRevert); @@ -220,8 +200,6 @@ library Address { * Requirements: * * - `customRevert` must be a reverting function. - * - * _Available since v5.0._ */ function verifyCallResult( bool success, diff --git a/contracts/utils/Base64.sol b/contracts/utils/Base64.sol index 9ba6defe0..ae73ec4af 100644 --- a/contracts/utils/Base64.sol +++ b/contracts/utils/Base64.sol @@ -5,8 +5,6 @@ pragma solidity ^0.8.19; /** * @dev Provides a set of functions to operate with Base64 strings. - * - * _Available since v4.5._ */ library Base64 { /** diff --git a/contracts/utils/Multicall.sol b/contracts/utils/Multicall.sol index fed9844c4..12c01ef11 100644 --- a/contracts/utils/Multicall.sol +++ b/contracts/utils/Multicall.sol @@ -7,8 +7,6 @@ import {Address} from "./Address.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. - * - * _Available since v4.1._ */ abstract contract Multicall { /** diff --git a/contracts/utils/StorageSlot.sol b/contracts/utils/StorageSlot.sol index b0e918967..cae1c8b68 100644 --- a/contracts/utils/StorageSlot.sol +++ b/contracts/utils/StorageSlot.sol @@ -27,9 +27,6 @@ pragma solidity ^0.8.19; * } * } * ``` - * - * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ - * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { diff --git a/contracts/utils/cryptography/ECDSA.sol b/contracts/utils/cryptography/ECDSA.sol index 5e67a7591..aabfb5ca2 100644 --- a/contracts/utils/cryptography/ECDSA.sol +++ b/contracts/utils/cryptography/ECDSA.sol @@ -63,8 +63,6 @@ library ECDSA { * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] - * - * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { if (signature.length == 65) { @@ -109,8 +107,6 @@ library ECDSA { * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] - * - * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { unchecked { @@ -123,8 +119,6 @@ library ECDSA { /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. - * - * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); @@ -135,8 +129,6 @@ library ECDSA { /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. - * - * _Available since v4.3._ */ function tryRecover( bytes32 hash, diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol index d94e956af..ff34e8146 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -28,8 +28,6 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * - * _Available since v3.4._ - * * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ abstract contract EIP712 is IERC5267 { @@ -111,8 +109,6 @@ abstract contract EIP712 is IERC5267 { /** * @dev See {IERC-5267}. - * - * _Available since v4.9._ */ function eip712Domain() public @@ -144,8 +140,6 @@ abstract contract EIP712 is IERC5267 { * * NOTE: By default this function reads _name which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). - * - * _Available since v5.0._ */ // solhint-disable-next-line func-name-mixedcase function _EIP712Name() internal view returns (string memory) { @@ -157,8 +151,6 @@ abstract contract EIP712 is IERC5267 { * * NOTE: By default this function reads _version which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). - * - * _Available since v5.0._ */ // solhint-disable-next-line func-name-mixedcase function _EIP712Version() internal view returns (string memory) { diff --git a/contracts/utils/cryptography/MerkleProof.sol b/contracts/utils/cryptography/MerkleProof.sol index 94586ff7b..17a6384fe 100644 --- a/contracts/utils/cryptography/MerkleProof.sol +++ b/contracts/utils/cryptography/MerkleProof.sol @@ -35,8 +35,6 @@ library MerkleProof { /** * @dev Calldata version of {verify} - * - * _Available since v4.7._ */ function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; @@ -47,8 +45,6 @@ library MerkleProof { * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. - * - * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; @@ -60,8 +56,6 @@ library MerkleProof { /** * @dev Calldata version of {processProof} - * - * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; @@ -76,8 +70,6 @@ library MerkleProof { * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. - * - * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, @@ -92,8 +84,6 @@ library MerkleProof { * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. - * - * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, @@ -113,8 +103,6 @@ library MerkleProof { * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). - * - * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, @@ -171,8 +159,6 @@ library MerkleProof { * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. - * - * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, diff --git a/contracts/utils/cryptography/SignatureChecker.sol b/contracts/utils/cryptography/SignatureChecker.sol index 5caf7bef9..f2cc2c4ed 100644 --- a/contracts/utils/cryptography/SignatureChecker.sol +++ b/contracts/utils/cryptography/SignatureChecker.sol @@ -10,8 +10,6 @@ import {IERC1271} from "../../interfaces/IERC1271.sol"; * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like * Argent and Safe Wallet (previously Gnosis Safe). - * - * _Available since v4.1._ */ library SignatureChecker { /** diff --git a/contracts/utils/introspection/ERC165Checker.sol b/contracts/utils/introspection/ERC165Checker.sol index d614c6755..86212695a 100644 --- a/contracts/utils/introspection/ERC165Checker.sol +++ b/contracts/utils/introspection/ERC165Checker.sol @@ -45,8 +45,6 @@ library ERC165Checker { * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. - * - * _Available since v3.4._ */ function getSupportedInterfaces( address account, diff --git a/contracts/utils/math/Math.sol b/contracts/utils/math/Math.sol index d372295d7..f55b69afc 100644 --- a/contracts/utils/math/Math.sol +++ b/contracts/utils/math/Math.sol @@ -20,8 +20,6 @@ library Math { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. - * - * _Available since v5.0._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { @@ -33,8 +31,6 @@ library Math { /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. - * - * _Available since v5.0._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { @@ -45,8 +41,6 @@ library Math { /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. - * - * _Available since v5.0._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { @@ -62,8 +56,6 @@ library Math { /** * @dev Returns the division of two unsigned integers, with a division by zero flag. - * - * _Available since v5.0._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { @@ -74,8 +66,6 @@ library Math { /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. - * - * _Available since v5.0._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { diff --git a/contracts/utils/math/SafeCast.sol b/contracts/utils/math/SafeCast.sol index d3b86b088..64f180cd2 100644 --- a/contracts/utils/math/SafeCast.sol +++ b/contracts/utils/math/SafeCast.sol @@ -46,8 +46,6 @@ library SafeCast { * Requirements: * * - input must fit into 248 bits - * - * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { @@ -65,8 +63,6 @@ library SafeCast { * Requirements: * * - input must fit into 240 bits - * - * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { @@ -84,8 +80,6 @@ library SafeCast { * Requirements: * * - input must fit into 232 bits - * - * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { @@ -103,8 +97,6 @@ library SafeCast { * Requirements: * * - input must fit into 224 bits - * - * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { @@ -122,8 +114,6 @@ library SafeCast { * Requirements: * * - input must fit into 216 bits - * - * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { @@ -141,8 +131,6 @@ library SafeCast { * Requirements: * * - input must fit into 208 bits - * - * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { @@ -160,8 +148,6 @@ library SafeCast { * Requirements: * * - input must fit into 200 bits - * - * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { @@ -179,8 +165,6 @@ library SafeCast { * Requirements: * * - input must fit into 192 bits - * - * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { @@ -198,8 +182,6 @@ library SafeCast { * Requirements: * * - input must fit into 184 bits - * - * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { @@ -217,8 +199,6 @@ library SafeCast { * Requirements: * * - input must fit into 176 bits - * - * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { @@ -236,8 +216,6 @@ library SafeCast { * Requirements: * * - input must fit into 168 bits - * - * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { @@ -255,8 +233,6 @@ library SafeCast { * Requirements: * * - input must fit into 160 bits - * - * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { @@ -274,8 +250,6 @@ library SafeCast { * Requirements: * * - input must fit into 152 bits - * - * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { @@ -293,8 +267,6 @@ library SafeCast { * Requirements: * * - input must fit into 144 bits - * - * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { @@ -312,8 +284,6 @@ library SafeCast { * Requirements: * * - input must fit into 136 bits - * - * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { @@ -331,8 +301,6 @@ library SafeCast { * Requirements: * * - input must fit into 128 bits - * - * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { @@ -350,8 +318,6 @@ library SafeCast { * Requirements: * * - input must fit into 120 bits - * - * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { @@ -369,8 +335,6 @@ library SafeCast { * Requirements: * * - input must fit into 112 bits - * - * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { @@ -388,8 +352,6 @@ library SafeCast { * Requirements: * * - input must fit into 104 bits - * - * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { @@ -407,8 +369,6 @@ library SafeCast { * Requirements: * * - input must fit into 96 bits - * - * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { @@ -426,8 +386,6 @@ library SafeCast { * Requirements: * * - input must fit into 88 bits - * - * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { @@ -445,8 +403,6 @@ library SafeCast { * Requirements: * * - input must fit into 80 bits - * - * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { @@ -464,8 +420,6 @@ library SafeCast { * Requirements: * * - input must fit into 72 bits - * - * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { @@ -483,8 +437,6 @@ library SafeCast { * Requirements: * * - input must fit into 64 bits - * - * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { @@ -502,8 +454,6 @@ library SafeCast { * Requirements: * * - input must fit into 56 bits - * - * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { @@ -521,8 +471,6 @@ library SafeCast { * Requirements: * * - input must fit into 48 bits - * - * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { @@ -540,8 +488,6 @@ library SafeCast { * Requirements: * * - input must fit into 40 bits - * - * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { @@ -559,8 +505,6 @@ library SafeCast { * Requirements: * * - input must fit into 32 bits - * - * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { @@ -578,8 +522,6 @@ library SafeCast { * Requirements: * * - input must fit into 24 bits - * - * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { @@ -597,8 +539,6 @@ library SafeCast { * Requirements: * * - input must fit into 16 bits - * - * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { @@ -616,8 +556,6 @@ library SafeCast { * Requirements: * * - input must fit into 8 bits - * - * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { @@ -632,8 +570,6 @@ library SafeCast { * Requirements: * * - input must be greater than or equal to 0. - * - * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { @@ -652,8 +588,6 @@ library SafeCast { * Requirements: * * - input must fit into 248 bits - * - * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); @@ -672,8 +606,6 @@ library SafeCast { * Requirements: * * - input must fit into 240 bits - * - * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); @@ -692,8 +624,6 @@ library SafeCast { * Requirements: * * - input must fit into 232 bits - * - * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); @@ -712,8 +642,6 @@ library SafeCast { * Requirements: * * - input must fit into 224 bits - * - * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); @@ -732,8 +660,6 @@ library SafeCast { * Requirements: * * - input must fit into 216 bits - * - * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); @@ -752,8 +678,6 @@ library SafeCast { * Requirements: * * - input must fit into 208 bits - * - * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); @@ -772,8 +696,6 @@ library SafeCast { * Requirements: * * - input must fit into 200 bits - * - * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); @@ -792,8 +714,6 @@ library SafeCast { * Requirements: * * - input must fit into 192 bits - * - * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); @@ -812,8 +732,6 @@ library SafeCast { * Requirements: * * - input must fit into 184 bits - * - * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); @@ -832,8 +750,6 @@ library SafeCast { * Requirements: * * - input must fit into 176 bits - * - * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); @@ -852,8 +768,6 @@ library SafeCast { * Requirements: * * - input must fit into 168 bits - * - * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); @@ -872,8 +786,6 @@ library SafeCast { * Requirements: * * - input must fit into 160 bits - * - * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); @@ -892,8 +804,6 @@ library SafeCast { * Requirements: * * - input must fit into 152 bits - * - * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); @@ -912,8 +822,6 @@ library SafeCast { * Requirements: * * - input must fit into 144 bits - * - * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); @@ -932,8 +840,6 @@ library SafeCast { * Requirements: * * - input must fit into 136 bits - * - * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); @@ -952,8 +858,6 @@ library SafeCast { * Requirements: * * - input must fit into 128 bits - * - * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); @@ -972,8 +876,6 @@ library SafeCast { * Requirements: * * - input must fit into 120 bits - * - * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); @@ -992,8 +894,6 @@ library SafeCast { * Requirements: * * - input must fit into 112 bits - * - * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); @@ -1012,8 +912,6 @@ library SafeCast { * Requirements: * * - input must fit into 104 bits - * - * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); @@ -1032,8 +930,6 @@ library SafeCast { * Requirements: * * - input must fit into 96 bits - * - * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); @@ -1052,8 +948,6 @@ library SafeCast { * Requirements: * * - input must fit into 88 bits - * - * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); @@ -1072,8 +966,6 @@ library SafeCast { * Requirements: * * - input must fit into 80 bits - * - * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); @@ -1092,8 +984,6 @@ library SafeCast { * Requirements: * * - input must fit into 72 bits - * - * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); @@ -1112,8 +1002,6 @@ library SafeCast { * Requirements: * * - input must fit into 64 bits - * - * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); @@ -1132,8 +1020,6 @@ library SafeCast { * Requirements: * * - input must fit into 56 bits - * - * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); @@ -1152,8 +1038,6 @@ library SafeCast { * Requirements: * * - input must fit into 48 bits - * - * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); @@ -1172,8 +1056,6 @@ library SafeCast { * Requirements: * * - input must fit into 40 bits - * - * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); @@ -1192,8 +1074,6 @@ library SafeCast { * Requirements: * * - input must fit into 32 bits - * - * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); @@ -1212,8 +1092,6 @@ library SafeCast { * Requirements: * * - input must fit into 24 bits - * - * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); @@ -1232,8 +1110,6 @@ library SafeCast { * Requirements: * * - input must fit into 16 bits - * - * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); @@ -1252,8 +1128,6 @@ library SafeCast { * Requirements: * * - input must fit into 8 bits - * - * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); @@ -1268,8 +1142,6 @@ library SafeCast { * Requirements: * * - input must be less than or equal to maxInt256. - * - * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive diff --git a/contracts/utils/structs/Checkpoints.sol b/contracts/utils/structs/Checkpoints.sol index 56b7035b9..6c73a08d8 100644 --- a/contracts/utils/structs/Checkpoints.sol +++ b/contracts/utils/structs/Checkpoints.sol @@ -12,8 +12,6 @@ import {Math} from "../math/Math.sol"; * * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new * checkpoint for the current transaction block using the {push} function. - * - * _Available since v4.5._ */ library Checkpoints { /** diff --git a/contracts/utils/structs/DoubleEndedQueue.sol b/contracts/utils/structs/DoubleEndedQueue.sol index 5183bad8c..30d953239 100644 --- a/contracts/utils/structs/DoubleEndedQueue.sol +++ b/contracts/utils/structs/DoubleEndedQueue.sol @@ -15,8 +15,6 @@ import {SafeCast} from "../math/SafeCast.sol"; * ```solidity * DoubleEndedQueue.Bytes32Deque queue; * ``` - * - * _Available since v4.6._ */ library DoubleEndedQueue { /** diff --git a/scripts/generate/templates/Checkpoints.js b/scripts/generate/templates/Checkpoints.js index d635c8462..3bd4589d2 100644 --- a/scripts/generate/templates/Checkpoints.js +++ b/scripts/generate/templates/Checkpoints.js @@ -13,8 +13,6 @@ import {Math} from "../math/Math.sol"; * * To create a history of checkpoints define a variable type \`Checkpoints.Trace*\` in your contract, and store a new * checkpoint for the current transaction block using the {push} function. - * - * _Available since v4.5._ */ `; diff --git a/scripts/generate/templates/SafeCast.js b/scripts/generate/templates/SafeCast.js index 6a4a80c2b..afc31a641 100644 --- a/scripts/generate/templates/SafeCast.js +++ b/scripts/generate/templates/SafeCast.js @@ -1,65 +1,8 @@ -const assert = require('assert'); const format = require('../format-lines'); const { range } = require('../../helpers'); const LENGTHS = range(8, 256, 8).reverse(); // 248 → 8 (in steps of 8) -// Returns the version of OpenZeppelin Contracts in which a particular function was introduced. -// This is used in the docs for each function. -const version = (selector, length) => { - switch (selector) { - case 'toUint(uint)': { - switch (length) { - case 8: - case 16: - case 32: - case 64: - case 128: - return '2.5'; - case 96: - case 224: - return '4.2'; - default: - assert(LENGTHS.includes(length)); - return '4.7'; - } - } - case 'toInt(int)': { - switch (length) { - case 8: - case 16: - case 32: - case 64: - case 128: - return '3.1'; - default: - assert(LENGTHS.includes(length)); - return '4.7'; - } - } - case 'toUint(int)': { - switch (length) { - case 256: - return '3.0'; - default: - assert(false); - return; - } - } - case 'toInt(uint)': { - switch (length) { - case 256: - return '3.0'; - default: - assert(false); - return; - } - } - default: - assert(false); - } -}; - const header = `\ pragma solidity ^0.8.19; @@ -109,8 +52,6 @@ const toUintDownCast = length => `\ * Requirements: * * - input must fit into ${length} bits - * - * _Available since v${version('toUint(uint)', length)}._ */ function toUint${length}(uint256 value) internal pure returns (uint${length}) { if (value > type(uint${length}).max) { @@ -132,8 +73,6 @@ const toIntDownCast = length => `\ * Requirements: * * - input must fit into ${length} bits - * - * _Available since v${version('toInt(int)', length)}._ */ function toInt${length}(int256 value) internal pure returns (int${length} downcasted) { downcasted = int${length}(value); @@ -151,8 +90,6 @@ const toInt = length => `\ * Requirements: * * - input must be less than or equal to maxInt${length}. - * - * _Available since v${version('toInt(uint)', length)}._ */ function toInt${length}(uint${length} value) internal pure returns (int${length}) { // Note: Unsafe cast below is okay because \`type(int${length}).max\` is guaranteed to be positive @@ -170,8 +107,6 @@ const toUint = length => `\ * Requirements: * * - input must be greater than or equal to 0. - * - * _Available since v${version('toUint(int)', length)}._ */ function toUint${length}(int${length} value) internal pure returns (uint${length}) { if (value < 0) { diff --git a/scripts/generate/templates/StorageSlot.js b/scripts/generate/templates/StorageSlot.js index 3e2263a0c..a9fa11fe3 100644 --- a/scripts/generate/templates/StorageSlot.js +++ b/scripts/generate/templates/StorageSlot.js @@ -1,22 +1,15 @@ const format = require('../format-lines'); -const { capitalize, unique } = require('../../helpers'); +const { capitalize } = require('../../helpers'); const TYPES = [ - { type: 'address', isValueType: true, version: '4.1' }, - { type: 'bool', isValueType: true, name: 'Boolean', version: '4.1' }, - { type: 'bytes32', isValueType: true, version: '4.1' }, - { type: 'uint256', isValueType: true, version: '4.1' }, - { type: 'string', isValueType: false, version: '4.9' }, - { type: 'bytes', isValueType: false, version: '4.9' }, + { type: 'address', isValueType: true }, + { type: 'bool', isValueType: true, name: 'Boolean' }, + { type: 'bytes32', isValueType: true }, + { type: 'uint256', isValueType: true }, + { type: 'string', isValueType: false }, + { type: 'bytes', isValueType: false }, ].map(type => Object.assign(type, { struct: (type.name ?? capitalize(type.type)) + 'Slot' })); -const VERSIONS = unique(TYPES.map(t => t.version)).map( - version => - `_Available since v${version} for ${TYPES.filter(t => t.version == version) - .map(t => `\`${t.type}\``) - .join(', ')}._`, -); - const header = `\ pragma solidity ^0.8.19; @@ -43,8 +36,6 @@ pragma solidity ^0.8.19; * } * } * \`\`\` - * -${VERSIONS.map(s => ` * ${s}`).join('\n')} */ `; diff --git a/scripts/upgradeable/upgradeable.patch b/scripts/upgradeable/upgradeable.patch index 8623806f5..ebf3aa4e2 100644 --- a/scripts/upgradeable/upgradeable.patch +++ b/scripts/upgradeable/upgradeable.patch @@ -126,7 +126,7 @@ index df141192..1cf90ad1 100644 "keywords": [ "solidity", diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol -index d94e956a..b2d3546f 100644 +index ff34e814..a9d08d5c 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -4,7 +4,6 @@ @@ -137,10 +137,10 @@ index d94e956a..b2d3546f 100644 import {IERC5267} from "../../interfaces/IERC5267.sol"; /** -@@ -29,28 +28,18 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; +@@ -27,28 +26,18 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; + * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain + * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. - * - * _Available since v3.4._ - * - * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ @@ -170,7 +170,7 @@ index d94e956a..b2d3546f 100644 /** * @dev Initializes the domain separator and parameter caches. -@@ -65,29 +54,23 @@ abstract contract EIP712 is IERC5267 { +@@ -63,29 +52,23 @@ abstract contract EIP712 is IERC5267 { * contract upgrade]. */ constructor(string memory name, string memory version) { @@ -208,7 +208,7 @@ index d94e956a..b2d3546f 100644 } /** -@@ -128,6 +111,10 @@ abstract contract EIP712 is IERC5267 { +@@ -124,6 +107,10 @@ abstract contract EIP712 is IERC5267 { uint256[] memory extensions ) { @@ -219,14 +219,12 @@ index d94e956a..b2d3546f 100644 return ( hex"0f", // 01111 _EIP712Name(), -@@ -142,26 +129,62 @@ abstract contract EIP712 is IERC5267 { +@@ -138,22 +125,62 @@ abstract contract EIP712 is IERC5267 { /** * @dev The name parameter for the EIP712 domain. * - * NOTE: By default this function reads _name which is an immutable value. - * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). -- * -- * _Available since v5.0._ + * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs + * are a concern. */ @@ -244,7 +242,10 @@ index d94e956a..b2d3546f 100644 - * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). + * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs + * are a concern. -+ */ + */ +- // solhint-disable-next-line func-name-mixedcase +- function _EIP712Version() internal view returns (string memory) { +- return _version.toStringWithFallback(_versionFallback); + function _EIP712Version() internal view virtual returns (string memory) { + return _version; + } @@ -272,13 +273,9 @@ index d94e956a..b2d3546f 100644 + + /** + * @dev The hash of the version parameter for the EIP712 domain. - * -- * _Available since v5.0._ ++ * + * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. - */ -- // solhint-disable-next-line func-name-mixedcase -- function _EIP712Version() internal view returns (string memory) { -- return _version.toStringWithFallback(_versionFallback); ++ */ + function _EIP712VersionHash() internal view returns (bytes32) { + string memory version = _EIP712Version(); + if (bytes(version).length > 0) { From 7ccea54dc15856d0e6c3b61b829b85d9e52195cd Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 6 Jul 2023 18:33:38 -0300 Subject: [PATCH 16/16] Add back IGovernor to docs (#4421) --- contracts/governance/README.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/governance/README.adoc b/contracts/governance/README.adoc index 29c3887c7..35f324b7e 100644 --- a/contracts/governance/README.adoc +++ b/contracts/governance/README.adoc @@ -52,6 +52,8 @@ NOTE: Functions of the `Governor` contract do not include access control. If you === Core +{{IGovernor}} + {{Governor}} === Modules