From c45d312e8af713b31094173aa701fc4791124895 Mon Sep 17 00:00:00 2001 From: Miljan Milidrag Date: Mon, 4 Mar 2024 09:46:36 +0100 Subject: [PATCH] Remove deps, and modify contracts to support the change --- contracts/external/WETH9.sol | 2 +- contracts/interfaces/IERC20.sol | 76 ++++++ contracts/libraries/external/SafeMath.sol | 156 ++++++++++++ contracts/mocks/Pool/P1MockLido.sol | 4 +- .../SwapOperator/SOMockEnzymeV4Vault.sol | 5 +- .../TokenController/TCMockGovernance.sol | 2 +- .../mocks/Tokens/ERC20CustomDecimalsMock.sol | 4 +- .../mocks/Tokens/ERC20MintableDetailed.sol | 4 +- contracts/mocks/Tokens/ERC20Mock.sol | 4 +- contracts/mocks/Tokens/ERC20MockNameable.sol | 4 +- .../Tokens/ERC20RevertingBalanceOfMock.sol | 4 +- contracts/mocks/Tokens/ERC721.sol | 231 ++++++++++++++++++ contracts/mocks/Tokens/ERC721Mock.sol | 24 +- contracts/mocks/common/ERC20Detailed.sol | 54 ++++ contracts/mocks/common/ERC20Mintable.sol | 23 ++ contracts/mocks/common/NXMTokenMock.sol | 2 +- contracts/modules/governance/Governance.sol | 2 +- contracts/modules/legacy/LegacyClaimsData.sol | 2 +- .../modules/legacy/LegacyQuotationData.sol | 2 +- contracts/modules/token/external/Context.sol | 27 ++ contracts/modules/token/external/ERC20.sol | 230 +++++++++++++++++ package-lock.json | 22 -- package.json | 2 - 23 files changed, 830 insertions(+), 56 deletions(-) create mode 100644 contracts/interfaces/IERC20.sol create mode 100644 contracts/libraries/external/SafeMath.sol create mode 100644 contracts/mocks/Tokens/ERC721.sol create mode 100644 contracts/mocks/common/ERC20Detailed.sol create mode 100644 contracts/mocks/common/ERC20Mintable.sol create mode 100644 contracts/modules/token/external/Context.sol create mode 100644 contracts/modules/token/external/ERC20.sol diff --git a/contracts/external/WETH9.sol b/contracts/external/WETH9.sol index 9031b6a60e..574f6477cb 100644 --- a/contracts/external/WETH9.sol +++ b/contracts/external/WETH9.sol @@ -2,7 +2,7 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "../interfaces/IERC20.sol"; contract WETH9 is IERC20 { string public name = "Wrapped Ether"; diff --git a/contracts/interfaces/IERC20.sol b/contracts/interfaces/IERC20.sol new file mode 100644 index 0000000000..134ad2115d --- /dev/null +++ b/contracts/interfaces/IERC20.sol @@ -0,0 +1,76 @@ +pragma solidity ^0.5.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. Does not include + * the optional functions; to access them see {ERC20Detailed}. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} diff --git a/contracts/libraries/external/SafeMath.sol b/contracts/libraries/external/SafeMath.sol new file mode 100644 index 0000000000..476ca9f428 --- /dev/null +++ b/contracts/libraries/external/SafeMath.sol @@ -0,0 +1,156 @@ +pragma solidity ^0.5.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return sub(a, b, "SafeMath: subtraction overflow"); + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * - Subtraction cannot overflow. + * + * _Available since v2.4.0._ + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + uint256 c = a - b; + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, "SafeMath: division by zero"); + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + * + * _Available since v2.4.0._ + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + // Solidity only automatically asserts when dividing by 0 + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return mod(a, b, "SafeMath: modulo by zero"); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts with custom message when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + * + * _Available since v2.4.0._ + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b != 0, errorMessage); + return a % b; + } +} diff --git a/contracts/mocks/Pool/P1MockLido.sol b/contracts/mocks/Pool/P1MockLido.sol index 24394ef515..217cdd028f 100644 --- a/contracts/mocks/Pool/P1MockLido.sol +++ b/contracts/mocks/Pool/P1MockLido.sol @@ -2,8 +2,8 @@ pragma solidity ^0.5.17; -import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; +import "../common/ERC20Detailed.sol"; +import "../common/ERC20Mintable.sol"; contract P1MockLido is ERC20Mintable, ERC20Detailed { diff --git a/contracts/mocks/SwapOperator/SOMockEnzymeV4Vault.sol b/contracts/mocks/SwapOperator/SOMockEnzymeV4Vault.sol index bd09080498..67e3f28270 100644 --- a/contracts/mocks/SwapOperator/SOMockEnzymeV4Vault.sol +++ b/contracts/mocks/SwapOperator/SOMockEnzymeV4Vault.sol @@ -2,9 +2,10 @@ pragma solidity ^0.5.17; -import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + import "../../external/enzyme/IEnzymeV4Vault.sol"; +import "../../modules/token/external/ERC20.sol"; +import "../common/ERC20Detailed.sol"; contract SOMockEnzymeV4Vault is IEnzymeV4Vault, ERC20Detailed, ERC20 { diff --git a/contracts/mocks/TokenController/TCMockGovernance.sol b/contracts/mocks/TokenController/TCMockGovernance.sol index 0e244c3271..1b7718b81c 100644 --- a/contracts/mocks/TokenController/TCMockGovernance.sol +++ b/contracts/mocks/TokenController/TCMockGovernance.sol @@ -2,7 +2,7 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../../libraries/external/SafeMath.sol"; import "../../abstract/LegacyMasterAware.sol"; import "../../interfaces/IGovernance.sol"; import "../../interfaces/IMemberRoles.sol"; diff --git a/contracts/mocks/Tokens/ERC20CustomDecimalsMock.sol b/contracts/mocks/Tokens/ERC20CustomDecimalsMock.sol index 58ecefb313..0519849d7b 100644 --- a/contracts/mocks/Tokens/ERC20CustomDecimalsMock.sol +++ b/contracts/mocks/Tokens/ERC20CustomDecimalsMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; +import "../common/ERC20Detailed.sol"; +import "../common/ERC20Mintable.sol"; contract ERC20CustomDecimalsMock is ERC20Mintable, ERC20Detailed { constructor(uint8 decimals) public diff --git a/contracts/mocks/Tokens/ERC20MintableDetailed.sol b/contracts/mocks/Tokens/ERC20MintableDetailed.sol index ab34e66fec..f48cf12043 100644 --- a/contracts/mocks/Tokens/ERC20MintableDetailed.sol +++ b/contracts/mocks/Tokens/ERC20MintableDetailed.sol @@ -2,8 +2,8 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; +import "../common/ERC20Detailed.sol"; +import "../common/ERC20Mintable.sol"; contract ERC20MintableDetailed is ERC20Mintable, ERC20Detailed { diff --git a/contracts/mocks/Tokens/ERC20Mock.sol b/contracts/mocks/Tokens/ERC20Mock.sol index 6814438cd6..62d4412580 100644 --- a/contracts/mocks/Tokens/ERC20Mock.sol +++ b/contracts/mocks/Tokens/ERC20Mock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; +import "../common/ERC20Detailed.sol"; +import "../common/ERC20Mintable.sol"; contract ERC20Mock is ERC20Mintable, ERC20Detailed { constructor() public ERC20Detailed("ERC20 mock", "MOCK", 18) { diff --git a/contracts/mocks/Tokens/ERC20MockNameable.sol b/contracts/mocks/Tokens/ERC20MockNameable.sol index 55c6e6ebd6..8d852b1d21 100644 --- a/contracts/mocks/Tokens/ERC20MockNameable.sol +++ b/contracts/mocks/Tokens/ERC20MockNameable.sol @@ -2,8 +2,8 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; +import "../common/ERC20Detailed.sol"; +import "../common/ERC20Mintable.sol"; contract ERC20MockNameable is ERC20Mintable, ERC20Detailed { constructor(string memory name, string memory symbol) public ERC20Detailed(name, symbol, 18) { diff --git a/contracts/mocks/Tokens/ERC20RevertingBalanceOfMock.sol b/contracts/mocks/Tokens/ERC20RevertingBalanceOfMock.sol index 5c2e3943e3..30a2043dbd 100644 --- a/contracts/mocks/Tokens/ERC20RevertingBalanceOfMock.sol +++ b/contracts/mocks/Tokens/ERC20RevertingBalanceOfMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; +import "../common/ERC20Detailed.sol"; +import "../common/ERC20Mintable.sol"; contract ERC20RevertingBalanceOfMock is ERC20Mintable, ERC20Detailed { diff --git a/contracts/mocks/Tokens/ERC721.sol b/contracts/mocks/Tokens/ERC721.sol new file mode 100644 index 0000000000..5ce81483bc --- /dev/null +++ b/contracts/mocks/Tokens/ERC721.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Modern, minimalist, and gas efficient ERC-721 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) +abstract contract ERC721 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 indexed id); + + event Approval(address indexed owner, address indexed spender, uint256 indexed id); + + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /*////////////////////////////////////////////////////////////// + METADATA STORAGE/LOGIC + //////////////////////////////////////////////////////////////*/ + + string public name; + + string public symbol; + + function tokenURI(uint256 id) public view virtual returns (string memory); + + /*////////////////////////////////////////////////////////////// + ERC721 BALANCE/OWNER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) internal _ownerOf; + + mapping(address => uint256) internal _balanceOf; + + function ownerOf(uint256 id) public view virtual returns (address owner) { + require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); + } + + function balanceOf(address owner) public view virtual returns (uint256) { + require(owner != address(0), "ZERO_ADDRESS"); + + return _balanceOf[owner]; + } + + /*////////////////////////////////////////////////////////////// + ERC721 APPROVAL STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) public getApproved; + + mapping(address => mapping(address => bool)) public isApprovedForAll; + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(string memory _name, string memory _symbol) { + name = _name; + symbol = _symbol; + } + + /*////////////////////////////////////////////////////////////// + ERC721 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 id) public virtual { + address owner = _ownerOf[id]; + + require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); + + getApproved[id] = spender; + + emit Approval(owner, spender, id); + } + + function setApprovalForAll(address operator, bool approved) public virtual { + isApprovedForAll[msg.sender][operator] = approved; + + emit ApprovalForAll(msg.sender, operator, approved); + } + + function transferFrom( + address from, + address to, + uint256 id + ) public virtual { + require(from == _ownerOf[id], "WRONG_FROM"); + + require(to != address(0), "INVALID_RECIPIENT"); + + require( + msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], + "NOT_AUTHORIZED" + ); + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + unchecked { + _balanceOf[from]--; + + _balanceOf[to]++; + } + + _ownerOf[id] = to; + + delete getApproved[id]; + + emit Transfer(from, to, id); + } + + function safeTransferFrom( + address from, + address to, + uint256 id + ) public virtual { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function safeTransferFrom( + address from, + address to, + uint256 id, + bytes calldata data + ) public virtual { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + /*////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return + interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 + interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 + interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 id) internal virtual { + require(to != address(0), "INVALID_RECIPIENT"); + + require(_ownerOf[id] == address(0), "ALREADY_MINTED"); + + // Counter overflow is incredibly unrealistic. + unchecked { + _balanceOf[to]++; + } + + _ownerOf[id] = to; + + emit Transfer(address(0), to, id); + } + + function _burn(uint256 id) internal virtual { + address owner = _ownerOf[id]; + + require(owner != address(0), "NOT_MINTED"); + + // Ownership check above ensures no underflow. + unchecked { + _balanceOf[owner]--; + } + + delete _ownerOf[id]; + + delete getApproved[id]; + + emit Transfer(owner, address(0), id); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL SAFE MINT LOGIC + //////////////////////////////////////////////////////////////*/ + + function _safeMint(address to, uint256 id) internal virtual { + _mint(to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _safeMint( + address to, + uint256 id, + bytes memory data + ) internal virtual { + _mint(to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } +} + +/// @notice A generic interface for a contract which properly accepts ERC721 tokens. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) +abstract contract ERC721TokenReceiver { + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) external virtual returns (bytes4) { + return ERC721TokenReceiver.onERC721Received.selector; + } +} diff --git a/contracts/mocks/Tokens/ERC721Mock.sol b/contracts/mocks/Tokens/ERC721Mock.sol index 846ec61172..111f236d4f 100644 --- a/contracts/mocks/Tokens/ERC721Mock.sol +++ b/contracts/mocks/Tokens/ERC721Mock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.18; -import "solmate/src/tokens/ERC721.sol"; +import "./ERC721.sol"; contract ERC721Mock is ERC721 { @@ -23,20 +23,20 @@ contract ERC721Mock is ERC721 { function _operatorTransferFrom(address from, address to, uint256 tokenId) internal { - require(from == _ownerOf[tokenId], "WRONG_FROM"); - require(to != address(0), "INVALID_RECIPIENT"); + require(from == _ownerOf[tokenId], "WRONG_FROM"); + require(to != address(0), "INVALID_RECIPIENT"); - // Underflow of the sender's balance is impossible because we check for - // ownership above and the recipient's balance can't realistically overflow. - unchecked { - _balanceOf[from]--; - _balanceOf[to]++; - } + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + unchecked { + _balanceOf[from]--; + _balanceOf[to]++; + } - _ownerOf[tokenId] = to; - delete getApproved[tokenId]; + _ownerOf[tokenId] = to; + delete getApproved[tokenId]; - emit Transfer(from, to, tokenId); + emit Transfer(from, to, tokenId); } } diff --git a/contracts/mocks/common/ERC20Detailed.sol b/contracts/mocks/common/ERC20Detailed.sol new file mode 100644 index 0000000000..bb8f47ad56 --- /dev/null +++ b/contracts/mocks/common/ERC20Detailed.sol @@ -0,0 +1,54 @@ +pragma solidity ^0.5.0; + +import "../../interfaces/IERC20.sol"; + +/** + * @dev Optional functions from the ERC20 standard. + */ +contract ERC20Detailed is IERC20 { + string private _name; + string private _symbol; + uint8 private _decimals; + + /** + * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of + * these values are immutable: they can only be set once during + * construction. + */ + constructor (string memory name, string memory symbol, uint8 decimals) public { + _name = name; + _symbol = symbol; + _decimals = decimals; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5,05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view returns (uint8) { + return _decimals; + } +} diff --git a/contracts/mocks/common/ERC20Mintable.sol b/contracts/mocks/common/ERC20Mintable.sol new file mode 100644 index 0000000000..6cdea9aae5 --- /dev/null +++ b/contracts/mocks/common/ERC20Mintable.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.5.0; + +import "../../modules/token/external/ERC20.sol"; + +/** + * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole}, + * which have permission to mint (create) new tokens as they see fit. + * + * At construction, the deployer of the contract is the only minter. + */ +contract ERC20Mintable is ERC20 { + /** + * @dev See {ERC20-_mint}. + * + * Requirements: + * + * - the caller must have the {MinterRole}. + */ + function mint(address account, uint256 amount) public returns (bool) { + _mint(account, amount); + return true; + } +} diff --git a/contracts/mocks/common/NXMTokenMock.sol b/contracts/mocks/common/NXMTokenMock.sol index 6a04462261..f8a8ff4c70 100644 --- a/contracts/mocks/common/NXMTokenMock.sol +++ b/contracts/mocks/common/NXMTokenMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.5.17; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "../../modules/token/external/ERC20.sol"; import "../../interfaces/INXMToken.sol"; contract NXMTokenMock is INXMToken, ERC20 { diff --git a/contracts/modules/governance/Governance.sol b/contracts/modules/governance/Governance.sol index 6c7957ed52..6e6136ee5d 100644 --- a/contracts/modules/governance/Governance.sol +++ b/contracts/modules/governance/Governance.sol @@ -2,7 +2,7 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../../libraries/external/SafeMath.sol"; import "../../abstract/LegacyMasterAware.sol"; import "../../interfaces/IGovernance.sol"; import "../../interfaces/IMemberRoles.sol"; diff --git a/contracts/modules/legacy/LegacyClaimsData.sol b/contracts/modules/legacy/LegacyClaimsData.sol index faf76947db..39a555f92f 100644 --- a/contracts/modules/legacy/LegacyClaimsData.sol +++ b/contracts/modules/legacy/LegacyClaimsData.sol @@ -2,7 +2,7 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../../libraries/external/SafeMath.sol"; import "../../abstract/LegacyMasterAware.sol"; import "../../interfaces/ILegacyClaimsData.sol"; diff --git a/contracts/modules/legacy/LegacyQuotationData.sol b/contracts/modules/legacy/LegacyQuotationData.sol index fa610a19ac..e150efd82a 100644 --- a/contracts/modules/legacy/LegacyQuotationData.sol +++ b/contracts/modules/legacy/LegacyQuotationData.sol @@ -2,7 +2,7 @@ pragma solidity ^0.5.0; -import "@openzeppelin/contracts/math/SafeMath.sol"; +import "../../libraries/external/SafeMath.sol"; import "../../abstract/LegacyMasterAware.sol"; contract LegacyQuotationData is LegacyMasterAware { diff --git a/contracts/modules/token/external/Context.sol b/contracts/modules/token/external/Context.sol new file mode 100644 index 0000000000..4db874da61 --- /dev/null +++ b/contracts/modules/token/external/Context.sol @@ -0,0 +1,27 @@ +pragma solidity ^0.5.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +contract Context { + // Empty internal constructor, to prevent people from mistakenly deploying + // an instance of this contract, which should be used via inheritance. + constructor () internal { } + // solhint-disable-previous-line no-empty-blocks + + function _msgSender() internal view returns (address payable) { + return msg.sender; + } + + function _msgData() internal view returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} diff --git a/contracts/modules/token/external/ERC20.sol b/contracts/modules/token/external/ERC20.sol new file mode 100644 index 0000000000..b72196b449 --- /dev/null +++ b/contracts/modules/token/external/ERC20.sol @@ -0,0 +1,230 @@ +pragma solidity ^0.5.0; + +import "./Context.sol"; +import "../../../interfaces/IERC20.sol"; +import "../../../libraries/external/SafeMath.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20Mintable}. + * + * TIP: For a detailed writeup see our guide + * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * We have followed general OpenZeppelin guidelines: functions revert instead + * of returning `false` on failure. This behavior is nonetheless conventional + * and does not conflict with the expectations of ERC20 applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ERC20 is Context, IERC20 { + using SafeMath for uint256; + + mapping (address => uint256) private _balances; + + mapping (address => mapping (address => uint256)) private _allowances; + + uint256 private _totalSupply; + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `recipient` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address recipient, uint256 amount) public returns (bool) { + _transfer(_msgSender(), recipient, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public returns (bool) { + _approve(_msgSender(), spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}; + * + * Requirements: + * - `sender` and `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + * - the caller must have allowance for `sender`'s tokens of at least + * `amount`. + */ + function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { + _transfer(sender, recipient, amount); + _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); + return true; + } + + /** + * @dev Moves tokens `amount` from `sender` to `recipient`. + * + * This is internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `sender` cannot be the zero address. + * - `recipient` cannot be the zero address. + * - `sender` must have a balance of at least `amount`. + */ + function _transfer(address sender, address recipient, uint256 amount) internal { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); + _balances[recipient] = _balances[recipient].add(amount); + emit Transfer(sender, recipient, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements + * + * - `to` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal { + require(account != address(0), "ERC20: mint to the zero address"); + + _totalSupply = _totalSupply.add(amount); + _balances[account] = _balances[account].add(amount); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal { + require(account != address(0), "ERC20: burn from the zero address"); + + _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. + * + * This is internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address owner, address spender, uint256 amount) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`.`amount` is then deducted + * from the caller's allowance. + * + * See {_burn} and {_approve}. + */ + function _burnFrom(address account, uint256 amount) internal { + _burn(account, amount); + _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); + } +} diff --git a/package-lock.json b/package-lock.json index 4ff33595d2..6b27a633d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "@nexusmutual/deployments": "^2.4.2", "@nomicfoundation/hardhat-network-helpers": "^1.0.8", - "@openzeppelin/contracts": "^2.5.1", "@openzeppelin/contracts-v4": "npm:@openzeppelin/contracts@^4.7.3", "dotenv": "^8.6.0", "ethereum-cryptography": "^1.0.1", @@ -20,7 +19,6 @@ "hardhat-ignore-warnings": "^0.2.8", "merkletreejs": "^0.2.32", "node-fetch": "^2.6.7", - "solmate": "^6.6.1", "workerpool": "^6.2.0" }, "devDependencies": { @@ -2108,11 +2106,6 @@ "semver": "bin/semver.js" } }, - "node_modules/@openzeppelin/contracts": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-2.5.1.tgz", - "integrity": "sha512-qIy6tLx8rtybEsIOAlrM4J/85s2q2nPkDqj/Rx46VakBZ0LwtFhXIVub96LXHczQX0vaqmAueDqNPXtbSXSaYQ==" - }, "node_modules/@openzeppelin/contracts-v4": { "name": "@openzeppelin/contracts", "version": "4.7.3", @@ -11834,11 +11827,6 @@ "node": ">=10" } }, - "node_modules/solmate": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/solmate/-/solmate-6.6.1.tgz", - "integrity": "sha512-WHvRXQvGtgR6R9nmkDTz/d+oULMqf/D33rlzQyadTX2SbuTmaW7ToEjGjGtWUVCQwZsZ/JP3vbOEVv7fB50btg==" - }, "node_modules/source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", @@ -15609,11 +15597,6 @@ } } }, - "@openzeppelin/contracts": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-2.5.1.tgz", - "integrity": "sha512-qIy6tLx8rtybEsIOAlrM4J/85s2q2nPkDqj/Rx46VakBZ0LwtFhXIVub96LXHczQX0vaqmAueDqNPXtbSXSaYQ==" - }, "@openzeppelin/contracts-v4": { "version": "npm:@openzeppelin/contracts@4.7.3", "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.7.3.tgz", @@ -23236,11 +23219,6 @@ } } }, - "solmate": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/solmate/-/solmate-6.6.1.tgz", - "integrity": "sha512-WHvRXQvGtgR6R9nmkDTz/d+oULMqf/D33rlzQyadTX2SbuTmaW7ToEjGjGtWUVCQwZsZ/JP3vbOEVv7fB50btg==" - }, "source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", diff --git a/package.json b/package.json index 6d2b4ce7bf..daab870c17 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "dependencies": { "@nexusmutual/deployments": "^2.4.2", "@nomicfoundation/hardhat-network-helpers": "^1.0.8", - "@openzeppelin/contracts": "^2.5.1", "@openzeppelin/contracts-v4": "npm:@openzeppelin/contracts@^4.7.3", "dotenv": "^8.6.0", "ethereum-cryptography": "^1.0.1", @@ -31,7 +30,6 @@ "hardhat-ignore-warnings": "^0.2.8", "merkletreejs": "^0.2.32", "node-fetch": "^2.6.7", - "solmate": "^6.6.1", "workerpool": "^6.2.0" }, "devDependencies": {