Commit 06f996b2 by github-actions

Transpile eb81c387

parent f130b81b
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
* `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754)) * `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754))
* `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768)) * `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768))
* `Governor`: added a modular system of `Governor` contracts based on `GovernorAlpha` and `GovernorBravo`. ([#2672](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2672)) * `Governor`: added a modular system of `Governor` contracts based on `GovernorAlpha` and `GovernorBravo`. ([#2672](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2672))
* Add an `interfaces` folder containing solidity interfaces to final ERCs. ([#2517](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2517))
* `ECDSA`: add `tryRecover` functions that will not throw if the signature is invalid, and will return an error flag instead. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661))
* `SignatureChecker`: Reduce gas usage of the `isValidSignatureNow` function for the "signature by EOA" case. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661))
* `ECDSA`: add `tryRecover` functions that will not throw if the signature is invalid, and will return an error flag instead. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661))
* `SignatureChecker`: Reduce gas usage of the `isValidSignatureNow` function for the "signature by EOA" case. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661))
## 4.2.0 (2021-06-30) ## 4.2.0 (2021-06-30)
......
...@@ -2,20 +2,12 @@ ...@@ -2,20 +2,12 @@
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
import "./IAccessControlEnumerableUpgradeable.sol";
import "./AccessControlUpgradeable.sol"; import "./AccessControlUpgradeable.sol";
import "../utils/structs/EnumerableSetUpgradeable.sol"; import "../utils/structs/EnumerableSetUpgradeable.sol";
import "../proxy/utils/Initializable.sol"; import "../proxy/utils/Initializable.sol";
/** /**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerableUpgradeable {
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role. * @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/ */
abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable { abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable {
...@@ -66,7 +58,7 @@ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessCo ...@@ -66,7 +58,7 @@ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessCo
/** /**
* @dev Overload {grantRole} to track enumerable memberships * @dev Overload {grantRole} to track enumerable memberships
*/ */
function grantRole(bytes32 role, address account) public virtual override { function grantRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControlUpgradeable) {
super.grantRole(role, account); super.grantRole(role, account);
_roleMembers[role].add(account); _roleMembers[role].add(account);
} }
...@@ -74,7 +66,7 @@ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessCo ...@@ -74,7 +66,7 @@ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessCo
/** /**
* @dev Overload {revokeRole} to track enumerable memberships * @dev Overload {revokeRole} to track enumerable memberships
*/ */
function revokeRole(bytes32 role, address account) public virtual override { function revokeRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControlUpgradeable) {
super.revokeRole(role, account); super.revokeRole(role, account);
_roleMembers[role].remove(account); _roleMembers[role].remove(account);
} }
...@@ -82,7 +74,7 @@ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessCo ...@@ -82,7 +74,7 @@ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessCo
/** /**
* @dev Overload {renounceRole} to track enumerable memberships * @dev Overload {renounceRole} to track enumerable memberships
*/ */
function renounceRole(bytes32 role, address account) public virtual override { function renounceRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControlUpgradeable) {
super.renounceRole(role, account); super.renounceRole(role, account);
_roleMembers[role].remove(account); _roleMembers[role].remove(account);
} }
......
...@@ -2,27 +2,13 @@ ...@@ -2,27 +2,13 @@
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol"; import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol"; import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol"; import "../proxy/utils/Initializable.sol";
/** /**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
/**
* @dev Contract module that allows children to implement role-based access * @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role * control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some * members except through off-chain means by accessing the contract event logs. Some
...@@ -79,33 +65,6 @@ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, ...@@ -79,33 +65,6 @@ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable,
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/** /**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `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);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Modifier that checks that an account has a specific role. Reverts * @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role. * with a standardized message including the required role.
* *
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `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);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
...@@ -12,6 +12,10 @@ This directory provides ways to restrict who can access the functions of a contr ...@@ -12,6 +12,10 @@ This directory provides ways to restrict who can access the functions of a contr
{{Ownable}} {{Ownable}}
{{IAccessControl}}
{{AccessControl}} {{AccessControl}}
{{IAccessControlEnumerable}}
{{AccessControlEnumerable}} {{AccessControlEnumerable}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC1155/extensions/IERC1155MetadataURIUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC1155/IERC1155ReceiverUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC1155/IERC1155Upgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC1363ReceiverUpgradeable {
/*
* Note: the ERC-165 identifier for this interface is 0x88a7ca5c.
* 0x88a7ca5c === bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))
*/
/**
* @notice Handle the receipt of ERC1363 tokens
* @dev Any ERC1363 smart contract calls this function on the recipient
* after a `transfer` or a `transferFrom`. This function MAY throw to revert and reject the
* transfer. Return of other than the magic value MUST result in the
* transaction being reverted.
* Note: the token contract address is always the message sender.
* @param operator address The address which called `transferAndCall` or `transferFromAndCall` function
* @param from address The address which are token transferred from
* @param value uint256 The amount of tokens transferred
* @param data bytes Additional data with no specified format
* @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))`
* unless throwing
*/
function onTransferReceived(
address operator,
address from,
uint256 value,
bytes memory data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC1363SpenderUpgradeable {
/*
* Note: the ERC-165 identifier for this interface is 0x7b04a2d0.
* 0x7b04a2d0 === bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))
*/
/**
* @notice Handle the approval of ERC1363 tokens
* @dev Any ERC1363 smart contract calls this function on the recipient
* after an `approve`. This function MAY throw to revert and reject the
* approval. Return of other than the magic value MUST result in the
* transaction being reverted.
* Note: the token contract address is always the message sender.
* @param owner address The address which called `approveAndCall` function
* @param value uint256 The amount of tokens to be spent
* @param data bytes Additional data with no specified format
* @return `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))`
* unless throwing
*/
function onApprovalReceived(
address owner,
uint256 value,
bytes memory data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20Upgradeable.sol";
import "./IERC165Upgradeable.sol";
interface IERC1363Upgradeable is IERC165Upgradeable, IERC20Upgradeable {
/*
* Note: the ERC-165 identifier for this interface is 0x4bbee2df.
* 0x4bbee2df ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)'))
*/
/*
* Note: the ERC-165 identifier for this interface is 0xfb9ec8ce.
* 0xfb9ec8ce ===
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver
* @param to address The address which you want to transfer to
* @param value uint256 The amount of tokens to be transferred
* @return true unless throwing
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver
* @param to address The address which you want to transfer to
* @param value uint256 The amount of tokens to be transferred
* @param data bytes Additional data with no specified format, sent in call to `to`
* @return true unless throwing
*/
function transferAndCall(
address to,
uint256 value,
bytes memory data
) external returns (bool);
/**
* @dev Transfer tokens from one address to another and then call `onTransferReceived` on receiver
* @param from address The address which you want to send tokens from
* @param to address The address which you want to transfer to
* @param value uint256 The amount of tokens to be transferred
* @return true unless throwing
*/
function transferFromAndCall(
address from,
address to,
uint256 value
) external returns (bool);
/**
* @dev Transfer tokens from one address to another and then call `onTransferReceived` on receiver
* @param from address The address which you want to send tokens from
* @param to address The address which you want to transfer to
* @param value uint256 The amount of tokens to be transferred
* @param data bytes Additional data with no specified format, sent in call to `to`
* @return true unless throwing
*/
function transferFromAndCall(
address from,
address to,
uint256 value,
bytes memory data
) external returns (bool);
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender
* and then call `onApprovalReceived` on spender.
* @param spender address The address which will spend the funds
* @param value uint256 The amount of tokens to be spent
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender
* and then call `onApprovalReceived` on spender.
* @param spender address The address which will spend the funds
* @param value uint256 The amount of tokens to be spent
* @param data bytes Additional data with no specified format, sent in call to `spender`
*/
function approveAndCall(
address spender,
uint256 value,
bytes memory data
) external returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165Upgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/introspection/IERC1820ImplementerUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/introspection/IERC1820RegistryUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20Upgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
/**
* @dev Interface for the NFT Royalty Standard
*/
interface IERC2981Upgradeable is IERC165Upgradeable {
/**
* @dev Called with the sale price to determine how much royalty is owed and to whom.
* @param tokenId - the NFT asset queried for royalty information
* @param salePrice - the sale price of the NFT asset specified by `tokenId`
* @return receiver - address of who should be sent the royalty payment
* @return royaltyAmount - the royalty payment amount for `salePrice`
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC3156 FlashBorrower, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*
* _Available since v4.1._
*/
interface IERC3156FlashBorrowerUpgradeable {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC3156FlashBorrowerUpgradeable.sol";
/**
* @dev Interface of the ERC3156 FlashLender, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*
* _Available since v4.1._
*/
interface IERC3156FlashLenderUpgradeable {
/**
* @dev The amount of currency available to be lended.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(address token) external view returns (uint256);
/**
* @dev The fee to be charged for a given loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(address token, uint256 amount) external view returns (uint256);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrowerUpgradeable receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}
...@@ -2,62 +2,5 @@ ...@@ -2,62 +2,5 @@
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
/** import "./IERC3156FlashBorrowerUpgradeable.sol";
* @dev Interface of the ERC3156 FlashBorrower, as defined in import "./IERC3156FlashLenderUpgradeable.sol";
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*
* _Available since v4.1._
*/
interface IERC3156FlashBorrowerUpgradeable {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}
/**
* @dev Interface of the ERC3156 FlashLender, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*/
interface IERC3156FlashLenderUpgradeable {
/**
* @dev The amount of currency available to be lended.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(address token) external view returns (uint256);
/**
* @dev The fee to be charged for a given loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(address token, uint256 amount) external view returns (uint256);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrowerUpgradeable receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/IERC721EnumerableUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/IERC721MetadataUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/IERC721ReceiverUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/IERC721Upgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC777/IERC777RecipientUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC777/IERC777SenderUpgradeable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC777/IERC777Upgradeable.sol";
= Interfaces
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils
== List of standardized interfaces
These interfaces are available as `.sol` files, and also as compiler `.json` ABI files (through the npm package). These
are usefull to interract with third party contracts that implement them.
- {IERC20}
- {IERC20Metadata}
- {IERC165}
- {IERC721}
- {IERC721Receiver}
- {IERC721Enumerable}
- {IERC721Metadata}
- {IERC777}
- {IERC777Recipient}
- {IERC777Sender}
- {IERC1155}
- {IERC1155Receiver}
- {IERC1155MetadataURI}
- {IERC1271}
- {IERC1363}
- {IERC1820Implementer}
- {IERC1820Registry}
- {IERC2612}
- {IERC2981}
- {IERC3156FlashLender}
- {IERC3156FlashBorrower}
== Detailed ABI
{{IERC1271}}
{{IERC1363}}
{{IERC1363Receiver}}
{{IERC1820Implementer}}
{{IERC1820Registry}}
{{IERC2612}}
{{IERC2981}}
{{IERC3156FlashLender}}
{{IERC3156FlashBorrower}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";
interface IERC2612Upgradeable is IERC20PermitUpgradeable {}
...@@ -18,6 +18,25 @@ contract ECDSAMockUpgradeable is Initializable { ...@@ -18,6 +18,25 @@ contract ECDSAMockUpgradeable is Initializable {
return hash.recover(signature); return hash.recover(signature);
} }
// solhint-disable-next-line func-name-mixedcase
function recover_v_r_s(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) public pure returns (address) {
return hash.recover(v, r, s);
}
// solhint-disable-next-line func-name-mixedcase
function recover_r_vs(
bytes32 hash,
bytes32 r,
bytes32 vs
) public pure returns (address) {
return hash.recover(r, vs);
}
function toEthSignedMessageHash(bytes32 hash) public pure returns (bytes32) { function toEthSignedMessageHash(bytes32 hash) public pure returns (bytes32) {
return hash.toEthSignedMessageHash(); return hash.toEthSignedMessageHash();
} }
......
...@@ -257,32 +257,6 @@ contract ERC1155ReceiverMockUpgradeableWithInit is ERC1155ReceiverMockUpgradeabl ...@@ -257,32 +257,6 @@ contract ERC1155ReceiverMockUpgradeableWithInit is ERC1155ReceiverMockUpgradeabl
__ERC1155ReceiverMock_init(recRetval, recReverts, batRetval, batReverts); __ERC1155ReceiverMock_init(recRetval, recReverts, batRetval, batReverts);
} }
} }
import "./ERC721URIStorageMockUpgradeable.sol";
contract ERC721URIStorageMockUpgradeableWithInit is ERC721URIStorageMockUpgradeable {
constructor(string memory name, string memory symbol) public payable {
__ERC721URIStorageMock_init(name, symbol);
}
}
import "./PausableMockUpgradeable.sol";
contract PausableMockUpgradeableWithInit is PausableMockUpgradeable {
constructor() public payable {
__PausableMock_init();
}
}
import "./ERC20PausableMockUpgradeable.sol";
contract ERC20PausableMockUpgradeableWithInit is ERC20PausableMockUpgradeable {
constructor(
string memory name,
string memory symbol,
address initialAccount,
uint256 initialBalance
) public payable {
__ERC20PausableMock_init(name, symbol, initialAccount, initialBalance);
}
}
import "../token/ERC1155/ERC1155Upgradeable.sol"; import "../token/ERC1155/ERC1155Upgradeable.sol";
contract ERC1155UpgradeableWithInit is ERC1155Upgradeable { contract ERC1155UpgradeableWithInit is ERC1155Upgradeable {
...@@ -332,39 +306,18 @@ contract EnumerableMapMockUpgradeableWithInit is EnumerableMapMockUpgradeable { ...@@ -332,39 +306,18 @@ contract EnumerableMapMockUpgradeableWithInit is EnumerableMapMockUpgradeable {
__EnumerableMapMock_init(); __EnumerableMapMock_init();
} }
} }
import "./ERC1155SupplyMockUpgradeable.sol"; import "./PausableMockUpgradeable.sol";
contract ERC1155SupplyMockUpgradeableWithInit is ERC1155SupplyMockUpgradeable {
constructor(string memory uri) public payable {
__ERC1155SupplyMock_init(uri);
}
}
import "./ERC1155MockUpgradeable.sol";
contract ERC1155MockUpgradeableWithInit is ERC1155MockUpgradeable {
constructor(string memory uri) public payable {
__ERC1155Mock_init(uri);
}
}
import "./ERC1155PausableMockUpgradeable.sol";
contract ERC1155PausableMockUpgradeableWithInit is ERC1155PausableMockUpgradeable {
constructor(string memory uri) public payable {
__ERC1155PausableMock_init(uri);
}
}
import "./ERC1155BurnableMockUpgradeable.sol";
contract ERC1155BurnableMockUpgradeableWithInit is ERC1155BurnableMockUpgradeable { contract PausableMockUpgradeableWithInit is PausableMockUpgradeable {
constructor(string memory uri) public payable { constructor() public payable {
__ERC1155BurnableMock_init(uri); __PausableMock_init();
} }
} }
import "./ERC721PausableMockUpgradeable.sol"; import "./ERC721URIStorageMockUpgradeable.sol";
contract ERC721PausableMockUpgradeableWithInit is ERC721PausableMockUpgradeable { contract ERC721URIStorageMockUpgradeableWithInit is ERC721URIStorageMockUpgradeable {
constructor(string memory name, string memory symbol) public payable { constructor(string memory name, string memory symbol) public payable {
__ERC721PausableMock_init(name, symbol); __ERC721URIStorageMock_init(name, symbol);
} }
} }
import "./ERC721MockUpgradeable.sol"; import "./ERC721MockUpgradeable.sol";
...@@ -374,41 +327,6 @@ contract ERC721MockUpgradeableWithInit is ERC721MockUpgradeable { ...@@ -374,41 +327,6 @@ contract ERC721MockUpgradeableWithInit is ERC721MockUpgradeable {
__ERC721Mock_init(name, symbol); __ERC721Mock_init(name, symbol);
} }
} }
import "./StringsMockUpgradeable.sol";
contract StringsMockUpgradeableWithInit is StringsMockUpgradeable {
constructor() public payable {
__StringsMock_init();
}
}
import "../token/ERC721/utils/ERC721HolderUpgradeable.sol";
contract ERC721HolderUpgradeableWithInit is ERC721HolderUpgradeable {
constructor() public payable {
__ERC721Holder_init();
}
}
import "./ERC721ReceiverMockUpgradeable.sol";
contract ERC721ReceiverMockUpgradeableWithInit is ERC721ReceiverMockUpgradeable {
constructor(bytes4 retval, Error error) public payable {
__ERC721ReceiverMock_init(retval, error);
}
}
import "./ERC721BurnableMockUpgradeable.sol";
contract ERC721BurnableMockUpgradeableWithInit is ERC721BurnableMockUpgradeable {
constructor(string memory name, string memory symbol) public payable {
__ERC721BurnableMock_init(name, symbol);
}
}
import "./ERC721EnumerableMockUpgradeable.sol";
contract ERC721EnumerableMockUpgradeableWithInit is ERC721EnumerableMockUpgradeable {
constructor(string memory name, string memory symbol) public payable {
__ERC721EnumerableMock_init(name, symbol);
}
}
import "./ERC165CheckerMockUpgradeable.sol"; import "./ERC165CheckerMockUpgradeable.sol";
contract ERC165CheckerMockUpgradeableWithInit is ERC165CheckerMockUpgradeable { contract ERC165CheckerMockUpgradeableWithInit is ERC165CheckerMockUpgradeable {
...@@ -430,27 +348,6 @@ contract ERC165InterfacesSupportedUpgradeableWithInit is ERC165InterfacesSupport ...@@ -430,27 +348,6 @@ contract ERC165InterfacesSupportedUpgradeableWithInit is ERC165InterfacesSupport
__ERC165InterfacesSupported_init(interfaceIds); __ERC165InterfacesSupported_init(interfaceIds);
} }
} }
import "../token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
contract ERC1155HolderUpgradeableWithInit is ERC1155HolderUpgradeable {
constructor() public payable {
__ERC1155Holder_init();
}
}
import "./ERC165StorageMockUpgradeable.sol";
contract ERC165StorageMockUpgradeableWithInit is ERC165StorageMockUpgradeable {
constructor() public payable {
__ERC165StorageMock_init();
}
}
import "./ERC165MockUpgradeable.sol";
contract ERC165MockUpgradeableWithInit is ERC165MockUpgradeable {
constructor() public payable {
__ERC165Mock_init();
}
}
import "./SafeERC20HelperUpgradeable.sol"; import "./SafeERC20HelperUpgradeable.sol";
contract ERC20ReturnFalseMockUpgradeableWithInit is ERC20ReturnFalseMockUpgradeable { contract ERC20ReturnFalseMockUpgradeableWithInit is ERC20ReturnFalseMockUpgradeable {
...@@ -490,6 +387,17 @@ contract TokenTimelockUpgradeableWithInit is TokenTimelockUpgradeable { ...@@ -490,6 +387,17 @@ contract TokenTimelockUpgradeableWithInit is TokenTimelockUpgradeable {
__TokenTimelock_init(token_, beneficiary_, releaseTime_); __TokenTimelock_init(token_, beneficiary_, releaseTime_);
} }
} }
import "./ERC20WrapperMockUpgradeable.sol";
contract ERC20WrapperMockUpgradeableWithInit is ERC20WrapperMockUpgradeable {
constructor(
IERC20Upgradeable _underlyingToken,
string memory name,
string memory symbol
) public payable {
__ERC20WrapperMock_init(_underlyingToken, name, symbol);
}
}
import "../token/ERC777/ERC777Upgradeable.sol"; import "../token/ERC777/ERC777Upgradeable.sol";
contract ERC777UpgradeableWithInit is ERC777Upgradeable { contract ERC777UpgradeableWithInit is ERC777Upgradeable {
...@@ -574,15 +482,107 @@ contract ERC20FlashMintMockUpgradeableWithInit is ERC20FlashMintMockUpgradeable ...@@ -574,15 +482,107 @@ contract ERC20FlashMintMockUpgradeableWithInit is ERC20FlashMintMockUpgradeable
__ERC20FlashMintMock_init(name, symbol, initialAccount, initialBalance); __ERC20FlashMintMock_init(name, symbol, initialAccount, initialBalance);
} }
} }
import "./ERC20WrapperMockUpgradeable.sol"; import "./ERC721EnumerableMockUpgradeable.sol";
contract ERC20WrapperMockUpgradeableWithInit is ERC20WrapperMockUpgradeable { contract ERC721EnumerableMockUpgradeableWithInit is ERC721EnumerableMockUpgradeable {
constructor(string memory name, string memory symbol) public payable {
__ERC721EnumerableMock_init(name, symbol);
}
}
import "./StringsMockUpgradeable.sol";
contract StringsMockUpgradeableWithInit is StringsMockUpgradeable {
constructor() public payable {
__StringsMock_init();
}
}
import "../token/ERC721/utils/ERC721HolderUpgradeable.sol";
contract ERC721HolderUpgradeableWithInit is ERC721HolderUpgradeable {
constructor() public payable {
__ERC721Holder_init();
}
}
import "./ERC721ReceiverMockUpgradeable.sol";
contract ERC721ReceiverMockUpgradeableWithInit is ERC721ReceiverMockUpgradeable {
constructor(bytes4 retval, Error error) public payable {
__ERC721ReceiverMock_init(retval, error);
}
}
import "./ERC721BurnableMockUpgradeable.sol";
contract ERC721BurnableMockUpgradeableWithInit is ERC721BurnableMockUpgradeable {
constructor(string memory name, string memory symbol) public payable {
__ERC721BurnableMock_init(name, symbol);
}
}
import "./ERC721PausableMockUpgradeable.sol";
contract ERC721PausableMockUpgradeableWithInit is ERC721PausableMockUpgradeable {
constructor(string memory name, string memory symbol) public payable {
__ERC721PausableMock_init(name, symbol);
}
}
import "./ERC20PausableMockUpgradeable.sol";
contract ERC20PausableMockUpgradeableWithInit is ERC20PausableMockUpgradeable {
constructor( constructor(
IERC20Upgradeable _underlyingToken,
string memory name, string memory name,
string memory symbol string memory symbol,
address initialAccount,
uint256 initialBalance
) public payable { ) public payable {
__ERC20WrapperMock_init(_underlyingToken, name, symbol); __ERC20PausableMock_init(name, symbol, initialAccount, initialBalance);
}
}
import "./ERC1155PausableMockUpgradeable.sol";
contract ERC1155PausableMockUpgradeableWithInit is ERC1155PausableMockUpgradeable {
constructor(string memory uri) public payable {
__ERC1155PausableMock_init(uri);
}
}
import "./ERC1155MockUpgradeable.sol";
contract ERC1155MockUpgradeableWithInit is ERC1155MockUpgradeable {
constructor(string memory uri) public payable {
__ERC1155Mock_init(uri);
}
}
import "./ERC1155SupplyMockUpgradeable.sol";
contract ERC1155SupplyMockUpgradeableWithInit is ERC1155SupplyMockUpgradeable {
constructor(string memory uri) public payable {
__ERC1155SupplyMock_init(uri);
}
}
import "./ERC1155BurnableMockUpgradeable.sol";
contract ERC1155BurnableMockUpgradeableWithInit is ERC1155BurnableMockUpgradeable {
constructor(string memory uri) public payable {
__ERC1155BurnableMock_init(uri);
}
}
import "../token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
contract ERC1155HolderUpgradeableWithInit is ERC1155HolderUpgradeable {
constructor() public payable {
__ERC1155Holder_init();
}
}
import "./ERC165StorageMockUpgradeable.sol";
contract ERC165StorageMockUpgradeableWithInit is ERC165StorageMockUpgradeable {
constructor() public payable {
__ERC165StorageMock_init();
}
}
import "./ERC165MockUpgradeable.sol";
contract ERC165MockUpgradeableWithInit is ERC165MockUpgradeable {
constructor() public payable {
__ERC165Mock_init();
} }
} }
import "./ReentrancyAttackUpgradeable.sol"; import "./ReentrancyAttackUpgradeable.sol";
......
...@@ -9,9 +9,31 @@ pragma solidity ^0.8.0; ...@@ -9,9 +9,31 @@ pragma solidity ^0.8.0;
* of the private keys of a given address. * of the private keys of a given address.
*/ */
library ECDSAUpgradeable { library ECDSAUpgradeable {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/** /**
* @dev Returns the address that signed a hashed message (`hash`) with * @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes. * `signature` or error string. This address can then be used for verification purposes.
* *
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower * this function rejects them by requiring the `s` value to be in the lower
...@@ -26,8 +48,10 @@ library ECDSAUpgradeable { ...@@ -26,8 +48,10 @@ library ECDSAUpgradeable {
* Documentation for signature generation: * Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - 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] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/ */
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
// Check the signature length // Check the signature length
// - case 65: r,s,v signature (standard) // - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
...@@ -42,7 +66,7 @@ library ECDSAUpgradeable { ...@@ -42,7 +66,7 @@ library ECDSAUpgradeable {
s := mload(add(signature, 0x40)) s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60))) v := byte(0, mload(add(signature, 0x60)))
} }
return recover(hash, v, r, s); return tryRecover(hash, v, r, s);
} else if (signature.length == 64) { } else if (signature.length == 64) {
bytes32 r; bytes32 r;
bytes32 vs; bytes32 vs;
...@@ -52,42 +76,80 @@ library ECDSAUpgradeable { ...@@ -52,42 +76,80 @@ library ECDSAUpgradeable {
r := mload(add(signature, 0x20)) r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40)) vs := mload(add(signature, 0x40))
} }
return recover(hash, r, vs); return tryRecover(hash, r, vs);
} else { } else {
revert("ECDSA: invalid signature length"); return (address(0), RecoverError.InvalidSignatureLength);
} }
} }
/** /**
* @dev Overload of {ECDSA-recover} that receives the `r` and `vs` short-signature fields separately. * @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @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] * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
* *
* _Available since v4.2._ * _Available since v4.3._
*/ */
function recover( function tryRecover(
bytes32 hash, bytes32 hash,
bytes32 r, bytes32 r,
bytes32 vs bytes32 vs
) internal pure returns (address) { ) internal pure returns (address, RecoverError) {
bytes32 s; bytes32 s;
uint8 v; uint8 v;
assembly { assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27) v := add(shr(255, vs), 27)
} }
return recover(hash, v, r, s); return tryRecover(hash, v, r, s);
} }
/** /**
* @dev Overload of {ECDSA-recover} that receives the `v`, `r` and `s` signature fields separately. * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/ */
function recover( function recover(
bytes32 hash, bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v, uint8 v,
bytes32 r, bytes32 r,
bytes32 s bytes32 s
) internal pure returns (address) { ) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
...@@ -97,17 +159,35 @@ library ECDSAUpgradeable { ...@@ -97,17 +159,35 @@ library ECDSAUpgradeable {
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well. // these malleable signatures as well.
require( if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, return (address(0), RecoverError.InvalidSignatureS);
"ECDSA: invalid signature 's' value" }
); if (v != 27 && v != 28) {
require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value"); return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer address // If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s); address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "ECDSA: invalid signature"); if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return signer; return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
} }
/** /**
......
...@@ -22,14 +22,14 @@ library SignatureCheckerUpgradeable { ...@@ -22,14 +22,14 @@ library SignatureCheckerUpgradeable {
bytes32 hash, bytes32 hash,
bytes memory signature bytes memory signature
) internal view returns (bool) { ) internal view returns (bool) {
if (AddressUpgradeable.isContract(signer)) { (address recovered, ECDSAUpgradeable.RecoverError error) = ECDSAUpgradeable.tryRecover(hash, signature);
try IERC1271Upgradeable(signer).isValidSignature(hash, signature) returns (bytes4 magicValue) { if (error == ECDSAUpgradeable.RecoverError.NoError && recovered == signer) {
return magicValue == IERC1271Upgradeable.isValidSignature.selector; return true;
} catch {
return false;
}
} else {
return ECDSAUpgradeable.recover(hash, signature) == signer;
} }
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271Upgradeable.isValidSignature.selector, hash, signature)
);
return (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271Upgradeable.isValidSignature.selector);
} }
} }
...@@ -10,7 +10,12 @@ const WRONG_MESSAGE = web3.utils.sha3('Nope'); ...@@ -10,7 +10,12 @@ const WRONG_MESSAGE = web3.utils.sha3('Nope');
function to2098Format (signature) { function to2098Format (signature) {
const long = web3.utils.hexToBytes(signature); const long = web3.utils.hexToBytes(signature);
expect(long.length).to.be.equal(65); if (long.length !== 65) {
throw new Error('invalid signature length (expected long format)');
}
if (long[32] >> 7 === 1) {
throw new Error('invalid signature \'s\' value');
}
const short = long.slice(0, 64); const short = long.slice(0, 64);
short[32] |= (long[64] % 27) << 7; // set the first bit of the 32nd byte to the v parity bit short[32] |= (long[64] % 27) << 7; // set the first bit of the 32nd byte to the v parity bit
return web3.utils.bytesToHex(short); return web3.utils.bytesToHex(short);
...@@ -18,12 +23,33 @@ function to2098Format (signature) { ...@@ -18,12 +23,33 @@ function to2098Format (signature) {
function from2098Format (signature) { function from2098Format (signature) {
const short = web3.utils.hexToBytes(signature); const short = web3.utils.hexToBytes(signature);
expect(short.length).to.be.equal(64); if (short.length !== 64) {
throw new Error('invalid signature length (expected short format)');
}
short.push((short[32] >> 7) + 27); short.push((short[32] >> 7) + 27);
short[32] &= (1 << 7) - 1; // zero out the first bit of 1 the 32nd byte short[32] &= (1 << 7) - 1; // zero out the first bit of 1 the 32nd byte
return web3.utils.bytesToHex(short); return web3.utils.bytesToHex(short);
} }
function split (signature) {
const raw = web3.utils.hexToBytes(signature);
switch (raw.length) {
case 64:
return [
web3.utils.bytesToHex(raw.slice(0, 32)), // r
web3.utils.bytesToHex(raw.slice(32, 64)), // vs
];
case 65:
return [
raw[64], // v
web3.utils.bytesToHex(raw.slice(0, 32)), // r
web3.utils.bytesToHex(raw.slice(32, 64)), // s
];
default:
expect.fail('Invalid siganture length, cannot split');
}
}
contract('ECDSA', function (accounts) { contract('ECDSA', function (accounts) {
const [ other ] = accounts; const [ other ] = accounts;
...@@ -80,12 +106,18 @@ contract('ECDSA', function (accounts) { ...@@ -80,12 +106,18 @@ contract('ECDSA', function (accounts) {
const version = '00'; const version = '00';
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
await expectRevert(this.ecdsa.recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature \'v\' value'); await expectRevert(this.ecdsa.recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature \'v\' value');
await expectRevert(
this.ecdsa.recover_v_r_s(TEST_MESSAGE, ...split(signature)),
'ECDSA: invalid signature \'v\' value',
);
}); });
it('works with 27 as version value', async function () { it('works with 27 as version value', async function () {
const version = '1b'; // 27 = 1b. const version = '1b'; // 27 = 1b.
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
expect(await this.ecdsa.recover(TEST_MESSAGE, signature)).to.equal(signer); expect(await this.ecdsa.recover(TEST_MESSAGE, signature)).to.equal(signer);
expect(await this.ecdsa.recover_v_r_s(TEST_MESSAGE, ...split(signature))).to.equal(signer);
expect(await this.ecdsa.recover_r_vs(TEST_MESSAGE, ...split(to2098Format(signature)))).to.equal(signer);
}); });
it('reverts with wrong version', async function () { it('reverts with wrong version', async function () {
...@@ -94,6 +126,10 @@ contract('ECDSA', function (accounts) { ...@@ -94,6 +126,10 @@ contract('ECDSA', function (accounts) {
const version = '02'; const version = '02';
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
await expectRevert(this.ecdsa.recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature \'v\' value'); await expectRevert(this.ecdsa.recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature \'v\' value');
await expectRevert(
this.ecdsa.recover_v_r_s(TEST_MESSAGE, ...split(signature)),
'ECDSA: invalid signature \'v\' value',
);
}); });
it('works with short EIP2098 format', async function () { it('works with short EIP2098 format', async function () {
...@@ -113,12 +149,18 @@ contract('ECDSA', function (accounts) { ...@@ -113,12 +149,18 @@ contract('ECDSA', function (accounts) {
const version = '01'; const version = '01';
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
await expectRevert(this.ecdsa.recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature \'v\' value'); await expectRevert(this.ecdsa.recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature \'v\' value');
await expectRevert(
this.ecdsa.recover_v_r_s(TEST_MESSAGE, ...split(signature)),
'ECDSA: invalid signature \'v\' value',
);
}); });
it('works with 28 as version value', async function () { it('works with 28 as version value', async function () {
const version = '1c'; // 28 = 1c. const version = '1c'; // 28 = 1c.
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
expect(await this.ecdsa.recover(TEST_MESSAGE, signature)).to.equal(signer); expect(await this.ecdsa.recover(TEST_MESSAGE, signature)).to.equal(signer);
expect(await this.ecdsa.recover_v_r_s(TEST_MESSAGE, ...split(signature))).to.equal(signer);
expect(await this.ecdsa.recover_r_vs(TEST_MESSAGE, ...split(to2098Format(signature)))).to.equal(signer);
}); });
it('reverts with wrong version', async function () { it('reverts with wrong version', async function () {
...@@ -127,6 +169,10 @@ contract('ECDSA', function (accounts) { ...@@ -127,6 +169,10 @@ contract('ECDSA', function (accounts) {
const version = '02'; const version = '02';
const signature = signatureWithoutVersion + version; const signature = signatureWithoutVersion + version;
await expectRevert(this.ecdsa.recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature \'v\' value'); await expectRevert(this.ecdsa.recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature \'v\' value');
await expectRevert(
this.ecdsa.recover_v_r_s(TEST_MESSAGE, ...split(signature)),
'ECDSA: invalid signature \'v\' value',
);
}); });
it('works with short EIP2098 format', async function () { it('works with short EIP2098 format', async function () {
...@@ -141,8 +187,12 @@ contract('ECDSA', function (accounts) { ...@@ -141,8 +187,12 @@ contract('ECDSA', function (accounts) {
const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'; const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9';
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const highSSignature = '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b'; const highSSignature = '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b';
await expectRevert(this.ecdsa.recover(message, highSSignature), 'ECDSA: invalid signature \'s\' value'); await expectRevert(this.ecdsa.recover(message, highSSignature), 'ECDSA: invalid signature \'s\' value');
await expectRevert(
this.ecdsa.recover_v_r_s(TEST_MESSAGE, ...split(highSSignature)),
'ECDSA: invalid signature \'s\' value',
);
expect(() => to2098Format(highSSignature)).to.throw('invalid signature \'s\' value');
}); });
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment