diff -ruN .gitignore .gitignore --- .gitignore 1969-12-31 16:00:00.000000000 -0800 +++ .gitignore 2022-08-11 21:28:36.000000000 -0700 @@ -0,0 +1,2 @@ +* +!.gitignore diff -ruN access/AccessControl.sol access/AccessControl.sol --- access/AccessControl.sol 2022-08-11 21:28:00.000000000 -0700 +++ access/AccessControl.sol 2022-08-11 21:28:36.000000000 -0700 @@ -93,7 +93,7 @@ * * _Available since v4.6._ */ - function _checkRole(bytes32 role) internal view virtual { + function _checkRole(bytes32 role) public view virtual { // HARNESS: internal -> public _checkRole(role, _msgSender()); } diff -ruN access/Ownable.sol access/Ownable.sol --- access/Ownable.sol 2022-08-11 21:28:00.000000000 -0700 +++ access/Ownable.sol 2022-08-11 21:28:36.000000000 -0700 @@ -30,14 +30,6 @@ } /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - _checkOwner(); - _; - } - - /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { @@ -45,10 +37,11 @@ } /** - * @dev Throws if the sender is not the owner. + * @dev Throws if called by any account other than the owner. */ - function _checkOwner() internal view virtual { + modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; } /** diff -ruN governance/Governor.sol governance/Governor.sol --- governance/Governor.sol 2022-08-11 21:28:00.000000000 -0700 +++ governance/Governor.sol 2022-08-11 21:28:36.000000000 -0700 @@ -44,7 +44,7 @@ string private _name; - mapping(uint256 => ProposalCore) private _proposals; + mapping(uint256 => ProposalCore) internal _proposals; // This queue keeps track of the governor operating on itself. Calls to functions protected by the // {onlyGovernance} modifier needs to be whitelisted in this queue. Whitelisting is set in {_beforeExecute}, diff -ruN governance/TimelockController.sol governance/TimelockController.sol --- governance/TimelockController.sol 2022-08-11 21:28:00.000000000 -0700 +++ governance/TimelockController.sol 2022-08-11 21:28:36.000000000 -0700 @@ -28,10 +28,10 @@ bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); - uint256 internal constant _DONE_TIMESTAMP = uint256(1); + uint256 public constant _DONE_TIMESTAMP = uint256(1); mapping(bytes32 => uint256) private _timestamps; - uint256 private _minDelay; + uint256 public _minDelay; /** * @dev Emitted when a call is scheduled as part of operation `id`. diff -ruN governance/extensions/GovernorCountingSimple.sol governance/extensions/GovernorCountingSimple.sol --- governance/extensions/GovernorCountingSimple.sol 2022-08-11 21:28:00.000000000 -0700 +++ governance/extensions/GovernorCountingSimple.sol 2022-08-11 21:28:36.000000000 -0700 @@ -27,7 +27,7 @@ mapping(address => bool) hasVoted; } - mapping(uint256 => ProposalVote) private _proposalVotes; + mapping(uint256 => ProposalVote) internal _proposalVotes; /** * @dev See {IGovernor-COUNTING_MODE}. diff -ruN governance/extensions/GovernorPreventLateQuorum.sol governance/extensions/GovernorPreventLateQuorum.sol --- governance/extensions/GovernorPreventLateQuorum.sol 2022-08-11 21:28:00.000000000 -0700 +++ governance/extensions/GovernorPreventLateQuorum.sol 2022-08-11 21:28:36.000000000 -0700 @@ -21,8 +21,8 @@ using SafeCast for uint256; using Timers for Timers.BlockNumber; - uint64 private _voteExtension; - mapping(uint256 => Timers.BlockNumber) private _extendedDeadlines; + uint64 internal _voteExtension; // PRIVATE => INTERNAL + mapping(uint256 => Timers.BlockNumber) internal _extendedDeadlines; // PRIVATE => INTERNAL /// @dev Emitted when a proposal deadline is pushed back due to reaching quorum late in its voting period. event ProposalExtended(uint256 indexed proposalId, uint64 extendedDeadline); diff -ruN governance/utils/Votes.sol governance/utils/Votes.sol --- governance/utils/Votes.sol 2022-08-11 21:28:00.000000000 -0700 +++ governance/utils/Votes.sol 2022-08-11 21:28:36.000000000 -0700 @@ -35,7 +35,25 @@ bytes32 private constant _DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - mapping(address => address) private _delegation; + // HARNESS : Hooks cannot access any information from Checkpoints yet, so I am also updating votes and fromBlock in this struct + struct Ckpt { + uint32 fromBlock; + uint224 votes; + } + mapping(address => Ckpt) public _checkpoints; + + // HARNESSED getters + function numCheckpoints(address account) public view returns (uint32) { + return SafeCast.toUint32(_delegateCheckpoints[account]._checkpoints.length); + } + function ckptFromBlock(address account, uint32 pos) public view returns (uint32) { + return _delegateCheckpoints[account]._checkpoints[pos]._blockNumber; + } + function ckptVotes(address account, uint32 pos) public view returns (uint224) { + return _delegateCheckpoints[account]._checkpoints[pos]._value; + } + + mapping(address => address) public _delegation; mapping(address => Checkpoints.History) private _delegateCheckpoints; Checkpoints.History private _totalCheckpoints; @@ -124,7 +142,7 @@ * * Emits events {DelegateChanged} and {DelegateVotesChanged}. */ - function _delegate(address account, address delegatee) internal virtual { + function _delegate(address account, address delegatee) public virtual { address oldDelegate = delegates(account); _delegation[account] = delegatee; @@ -142,10 +160,10 @@ uint256 amount ) internal virtual { if (from == address(0)) { - _totalCheckpoints.push(_add, amount); + _totalCheckpoints.push(_totalCheckpoints.latest() + amount); // Harnessed to remove function pointers } if (to == address(0)) { - _totalCheckpoints.push(_subtract, amount); + _totalCheckpoints.push(_totalCheckpoints.latest() - amount); // Harnessed to remove function pointers } _moveDelegateVotes(delegates(from), delegates(to), amount); } @@ -160,11 +178,13 @@ ) private { if (from != to && amount > 0) { if (from != address(0)) { - (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount); + (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_delegateCheckpoints[from].latest() - amount); // HARNESSED TO REMOVE FUNCTION POINTERS + _checkpoints[from] = Ckpt({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newValue)}); // HARNESS emit DelegateVotesChanged(from, oldValue, newValue); } if (to != address(0)) { - (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount); + (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_delegateCheckpoints[to].latest() + amount); // HARNESSED TO REMOVE FUNCTION POINTERS + _checkpoints[to] = Ckpt({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newValue)}); // HARNESS emit DelegateVotesChanged(to, oldValue, newValue); } } @@ -207,5 +227,5 @@ /** * @dev Must return the voting units held by an account. */ - function _getVotingUnits(address) internal view virtual returns (uint256); + function _getVotingUnits(address) public virtual returns (uint256); // HARNESS: internal -> public } diff -ruN metatx/MinimalForwarder.sol metatx/MinimalForwarder.sol --- metatx/MinimalForwarder.sol 2022-08-11 21:28:00.000000000 -0700 +++ metatx/MinimalForwarder.sol 2022-08-11 21:28:36.000000000 -0700 @@ -8,11 +8,6 @@ /** * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}. - * - * MinimalForwarder is mainly meant for testing, as it is missing features to be a good production-ready forwarder. This - * contract does not intend to have all the properties that are needed for a sound forwarding system. A fully - * functioning forwarding system with good properties requires more complexity. We suggest you look at other projects - * such as the GSN which do have the goal of building a system like that. */ contract MinimalForwarder is EIP712 { using ECDSA for bytes32; diff -ruN mocks/ERC20TokenizedVaultMock.sol mocks/ERC20TokenizedVaultMock.sol --- mocks/ERC20TokenizedVaultMock.sol 1969-12-31 16:00:00.000000000 -0800 +++ mocks/ERC20TokenizedVaultMock.sol 2022-08-11 21:28:36.000000000 -0700 @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../token/ERC20/extensions/ERC20TokenizedVault.sol"; + +// mock class using ERC20 +contract ERC20TokenizedVaultMock is ERC20TokenizedVault { + constructor( + IERC20Metadata asset, + string memory name, + string memory symbol + ) ERC20(name, symbol) ERC20TokenizedVault(asset) {} + + function mockMint(address account, uint256 amount) public { + _mint(account, amount); + } + + function mockBurn(address account, uint256 amount) public { + _burn(account, amount); + } +} diff -ruN mocks/ERC4626Mock.sol mocks/ERC4626Mock.sol --- mocks/ERC4626Mock.sol 2022-08-11 21:28:00.000000000 -0700 +++ mocks/ERC4626Mock.sol 1969-12-31 16:00:00.000000000 -0800 @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "../token/ERC20/extensions/ERC4626.sol"; - -// mock class using ERC20 -contract ERC4626Mock is ERC4626 { - constructor( - IERC20Metadata asset, - string memory name, - string memory symbol - ) ERC20(name, symbol) ERC4626(asset) {} - - function mockMint(address account, uint256 amount) public { - _mint(account, amount); - } - - function mockBurn(address account, uint256 amount) public { - _burn(account, amount); - } -} diff -ruN mocks/MathMock.sol mocks/MathMock.sol --- mocks/MathMock.sol 2022-08-11 21:28:00.000000000 -0700 +++ mocks/MathMock.sol 2022-08-11 21:28:36.000000000 -0700 @@ -29,8 +29,4 @@ ) public pure returns (uint256) { return Math.mulDiv(a, b, denominator, direction); } - - function sqrt(uint256 a, Math.Rounding direction) public pure returns (uint256) { - return Math.sqrt(a, direction); - } } diff -ruN mocks/SafeERC20Helper.sol mocks/SafeERC20Helper.sol --- mocks/SafeERC20Helper.sol 2022-08-11 21:28:00.000000000 -0700 +++ mocks/SafeERC20Helper.sol 2022-08-11 21:28:36.000000000 -0700 @@ -4,7 +4,6 @@ import "../utils/Context.sol"; import "../token/ERC20/IERC20.sol"; -import "../token/ERC20/extensions/draft-ERC20Permit.sol"; import "../token/ERC20/utils/SafeERC20.sol"; contract ERC20ReturnFalseMock is Context { @@ -106,43 +105,6 @@ } } -contract ERC20PermitNoRevertMock is - ERC20("ERC20PermitNoRevertMock", "ERC20PermitNoRevertMock"), - ERC20Permit("ERC20PermitNoRevertMock") -{ - function getChainId() external view returns (uint256) { - return block.chainid; - } - - function permitThatMayRevert( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) public virtual { - super.permit(owner, spender, value, deadline, v, r, s); - } - - function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) public virtual override { - try this.permitThatMayRevert(owner, spender, value, deadline, v, r, s) { - // do nothing - } catch { - // do nothing - } - } -} - contract SafeERC20Wrapper is Context { using SafeERC20 for IERC20; @@ -172,18 +134,6 @@ _token.safeDecreaseAllowance(address(0), amount); } - function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) public { - SafeERC20.safePermit(IERC20Permit(address(_token)), owner, spender, value, deadline, v, r, s); - } - function setAllowance(uint256 allowance_) public { ERC20ReturnTrueMock(address(_token)).setAllowance(allowance_); } diff -ruN proxy/Clones.sol proxy/Clones.sol --- proxy/Clones.sol 2022-08-11 21:28:00.000000000 -0700 +++ proxy/Clones.sol 2022-08-11 21:28:36.000000000 -0700 @@ -26,10 +26,10 @@ /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) - mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) - mstore(add(ptr, 0x14), shl(0x60, implementation)) - mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) - instance := create(0, ptr, 0x37) + mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) + mstore(add(ptr, 0x13), shl(0x60, implementation)) + mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) + instance := create(0, ptr, 0x36) } require(instance != address(0), "ERC1167: create failed"); } @@ -45,10 +45,10 @@ /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) - mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) - mstore(add(ptr, 0x14), shl(0x60, implementation)) - mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) - instance := create2(0, ptr, 0x37, salt) + mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) + mstore(add(ptr, 0x13), shl(0x60, implementation)) + mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) + instance := create2(0, ptr, 0x36, salt) } require(instance != address(0), "ERC1167: create2 failed"); } @@ -64,13 +64,13 @@ /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) - mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) - mstore(add(ptr, 0x14), shl(0x60, implementation)) - mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) - mstore(add(ptr, 0x38), shl(0x60, deployer)) - mstore(add(ptr, 0x4c), salt) - mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) - predicted := keccak256(add(ptr, 0x37), 0x55) + mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) + mstore(add(ptr, 0x13), shl(0x60, implementation)) + mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) + mstore(add(ptr, 0x37), shl(0x60, deployer)) + mstore(add(ptr, 0x4b), salt) + mstore(add(ptr, 0x6b), keccak256(ptr, 0x36)) + predicted := keccak256(add(ptr, 0x36), 0x55) } } diff -ruN proxy/ERC1967/ERC1967Proxy.sol proxy/ERC1967/ERC1967Proxy.sol --- proxy/ERC1967/ERC1967Proxy.sol 2022-08-11 21:28:00.000000000 -0700 +++ proxy/ERC1967/ERC1967Proxy.sol 2022-08-11 21:28:36.000000000 -0700 @@ -20,6 +20,7 @@ * function call, and allows initializing the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) payable { + assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); _upgradeToAndCall(_logic, _data, false); } diff -ruN proxy/beacon/BeaconProxy.sol proxy/beacon/BeaconProxy.sol --- proxy/beacon/BeaconProxy.sol 2022-08-11 21:28:00.000000000 -0700 +++ proxy/beacon/BeaconProxy.sol 2022-08-11 21:28:36.000000000 -0700 @@ -28,6 +28,7 @@ * - `beacon` must be a contract with the interface {IBeacon}. */ constructor(address beacon, bytes memory data) payable { + assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1)); _upgradeBeaconToAndCall(beacon, data, false); } diff -ruN proxy/transparent/TransparentUpgradeableProxy.sol proxy/transparent/TransparentUpgradeableProxy.sol --- proxy/transparent/TransparentUpgradeableProxy.sol 2022-08-11 21:28:00.000000000 -0700 +++ proxy/transparent/TransparentUpgradeableProxy.sol 2022-08-11 21:28:36.000000000 -0700 @@ -36,6 +36,7 @@ address admin_, bytes memory _data ) payable ERC1967Proxy(_logic, _data) { + assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); _changeAdmin(admin_); } diff -ruN proxy/utils/Initializable.sol proxy/utils/Initializable.sol --- proxy/utils/Initializable.sol 2022-08-11 21:28:00.000000000 -0700 +++ proxy/utils/Initializable.sol 2022-08-11 21:28:36.000000000 -0700 @@ -59,12 +59,12 @@ * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ - uint8 private _initialized; + uint8 internal _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ - bool private _initializing; + bool internal _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. diff -ruN proxy/utils/Initializable.sol.orig proxy/utils/Initializable.sol.orig --- proxy/utils/Initializable.sol.orig 1969-12-31 16:00:00.000000000 -0800 +++ proxy/utils/Initializable.sol.orig 2022-08-11 21:28:36.000000000 -0700 @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol) + +pragma solidity ^0.8.2; + +import "../../utils/Address.sol"; + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ``` + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. + */ + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original + * initialization step. This is essential to configure modules that are added through upgrades and that require + * initialization. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + */ + modifier reinitializer(uint8 version) { + require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + */ + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized < type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } +} diff -ruN proxy/utils/Initializable.sol.rej proxy/utils/Initializable.sol.rej --- proxy/utils/Initializable.sol.rej 1969-12-31 16:00:00.000000000 -0800 +++ proxy/utils/Initializable.sol.rej 2022-08-11 21:28:36.000000000 -0700 @@ -0,0 +1,17 @@ +*************** +*** 130,136 **** + _setInitializedVersion(type(uint8).max); + } + +- function _setInitializedVersion(uint8 version) private returns (bool) { + // If the contract is initializing we ignore whether _initialized is set in order to support multiple + // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level + // of initializers, because in other contexts the contract may have been reentered. +--- 130,136 ---- + _setInitializedVersion(type(uint8).max); + } + ++ function _setInitializedVersion(uint8 version) internal returns (bool) { + // If the contract is initializing we ignore whether _initialized is set in order to support multiple + // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level + // of initializers, because in other contexts the contract may have been reentered. diff -ruN security/Pausable.sol security/Pausable.sol --- security/Pausable.sol 2022-08-11 21:28:00.000000000 -0700 +++ security/Pausable.sol 2022-08-11 21:28:36.000000000 -0700 @@ -35,6 +35,13 @@ } /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: @@ -42,7 +49,7 @@ * - The contract must not be paused. */ modifier whenNotPaused() { - _requireNotPaused(); + require(!paused(), "Pausable: paused"); _; } @@ -54,29 +61,8 @@ * - The contract must be paused. */ modifier whenPaused() { - _requirePaused(); - _; - } - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function paused() public view virtual returns (bool) { - return _paused; - } - - /** - * @dev Throws if the contract is paused. - */ - function _requireNotPaused() internal view virtual { - require(!paused(), "Pausable: paused"); - } - - /** - * @dev Throws if the contract is not paused. - */ - function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); + _; } /** diff -ruN token/ERC1155/ERC1155.sol token/ERC1155/ERC1155.sol --- token/ERC1155/ERC1155.sol 2022-08-11 21:28:00.000000000 -0700 +++ token/ERC1155/ERC1155.sol 2022-08-11 21:28:36.000000000 -0700 @@ -21,7 +21,7 @@ using Address for address; // Mapping from token ID to account balances - mapping(uint256 => mapping(address => uint256)) private _balances; + mapping(uint256 => mapping(address => uint256)) internal _balances; // MUNGED private => internal // Mapping from account to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; @@ -471,7 +471,7 @@ uint256 id, uint256 amount, bytes memory data - ) private { + ) public { // HARNESS: private -> public if (to.isContract()) { try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { if (response != IERC1155Receiver.onERC1155Received.selector) { @@ -492,7 +492,7 @@ uint256[] memory ids, uint256[] memory amounts, bytes memory data - ) private { + ) public { // HARNESS: private -> public if (to.isContract()) { try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( bytes4 response diff -ruN token/ERC20/ERC20.sol token/ERC20/ERC20.sol --- token/ERC20/ERC20.sol 2022-08-11 21:28:00.000000000 -0700 +++ token/ERC20/ERC20.sol 2022-08-11 23:01:50.000000000 -0700 @@ -277,7 +277,7 @@ * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ - function _burn(address account, uint256 amount) internal virtual { + function _burn(address account, uint256 amount) public virtual { // HARNESS: internal -> public require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); diff -ruN token/ERC20/README.adoc token/ERC20/README.adoc --- token/ERC20/README.adoc 2022-08-11 21:28:00.000000000 -0700 +++ token/ERC20/README.adoc 2022-08-11 21:28:36.000000000 -0700 @@ -24,7 +24,7 @@ * {ERC20Votes}: support for voting and vote delegation. * {ERC20VotesComp}: support for voting and vote delegation (compatible with Compound's token, with uint96 restrictions). * {ERC20Wrapper}: wrapper to create an ERC20 backed by another ERC20, with deposit and withdraw methods. Useful in conjunction with {ERC20Votes}. -* {ERC4626}: tokenized vault that manages shares (represented as ERC20) that are backed by assets (another ERC20). +* {ERC20TokenizedVault}: tokenized vault that manages shares (represented as ERC20) that are backed by assets (another ERC20). Finally, there are some utilities to interact with ERC20 contracts in various ways. @@ -63,7 +63,7 @@ {{ERC20FlashMint}} -{{ERC4626}} +{{ERC20TokenizedVault}} == Draft EIPs diff -ruN token/ERC20/extensions/ERC20FlashMint.sol token/ERC20/extensions/ERC20FlashMint.sol --- token/ERC20/extensions/ERC20FlashMint.sol 2022-08-11 21:28:00.000000000 -0700 +++ token/ERC20/extensions/ERC20FlashMint.sol 2022-08-11 21:28:36.000000000 -0700 @@ -40,9 +40,11 @@ require(token == address(this), "ERC20FlashMint: wrong token"); // silence warning about unused variable without the addition of bytecode. amount; - return 0; + return fee; // HARNESS: made "return" nonzero } + uint256 public fee; // HARNESS: added it to simulate random fee amount + /** * @dev Returns the receiver address of the flash fee. By default this * implementation returns the address(0) which means the fee amount will be burnt. diff -ruN token/ERC20/extensions/ERC20TokenizedVault.sol token/ERC20/extensions/ERC20TokenizedVault.sol --- token/ERC20/extensions/ERC20TokenizedVault.sol 1969-12-31 16:00:00.000000000 -0800 +++ token/ERC20/extensions/ERC20TokenizedVault.sol 2022-08-11 21:28:36.000000000 -0700 @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../utils/SafeERC20.sol"; +import "../../../interfaces/IERC4626.sol"; +import "../../../utils/math/Math.sol"; + +/** + * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in + * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626]. + * + * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for + * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends + * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this + * contract and not the "assets" token which is an independent contract. + * + * _Available since v4.7._ + */ +abstract contract ERC20TokenizedVault is ERC20, IERC4626 { + using Math for uint256; + + IERC20Metadata private immutable _asset; + + /** + * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777). + */ + constructor(IERC20Metadata asset_) { + _asset = asset_; + } + + /** @dev See {IERC4262-asset} */ + function asset() public view virtual override returns (address) { + return address(_asset); + } + + /** @dev See {IERC4262-totalAssets} */ + function totalAssets() public view virtual override returns (uint256) { + return _asset.balanceOf(address(this)); + } + + /** @dev See {IERC4262-convertToShares} */ + function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) { + return _convertToShares(assets, Math.Rounding.Down); + } + + /** @dev See {IERC4262-convertToAssets} */ + function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) { + return _convertToAssets(shares, Math.Rounding.Down); + } + + /** @dev See {IERC4262-maxDeposit} */ + function maxDeposit(address) public view virtual override returns (uint256) { + return _isVaultCollateralized() ? type(uint256).max : 0; + } + + /** @dev See {IERC4262-maxMint} */ + function maxMint(address) public view virtual override returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4262-maxWithdraw} */ + function maxWithdraw(address owner) public view virtual override returns (uint256) { + return _convertToAssets(balanceOf(owner), Math.Rounding.Down); + } + + /** @dev See {IERC4262-maxRedeem} */ + function maxRedeem(address owner) public view virtual override returns (uint256) { + return balanceOf(owner); + } + + /** @dev See {IERC4262-previewDeposit} */ + function previewDeposit(uint256 assets) public view virtual override returns (uint256) { + return _convertToShares(assets, Math.Rounding.Down); + } + + /** @dev See {IERC4262-previewMint} */ + function previewMint(uint256 shares) public view virtual override returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Up); + } + + /** @dev See {IERC4262-previewWithdraw} */ + function previewWithdraw(uint256 assets) public view virtual override returns (uint256) { + return _convertToShares(assets, Math.Rounding.Up); + } + + /** @dev See {IERC4262-previewRedeem} */ + function previewRedeem(uint256 shares) public view virtual override returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Down); + } + + /** @dev See {IERC4262-deposit} */ + function deposit(uint256 assets, address receiver) public virtual override returns (uint256) { + require(assets <= maxDeposit(receiver), "ERC20TokenizedVault: deposit more than max"); + + uint256 shares = previewDeposit(assets); + _deposit(_msgSender(), receiver, assets, shares); + + return shares; + } + + /** @dev See {IERC4262-mint} */ + function mint(uint256 shares, address receiver) public virtual override returns (uint256) { + require(shares <= maxMint(receiver), "ERC20TokenizedVault: mint more than max"); + + uint256 assets = previewMint(shares); + _deposit(_msgSender(), receiver, assets, shares); + + return assets; + } + + /** @dev See {IERC4262-withdraw} */ + function withdraw( + uint256 assets, + address receiver, + address owner + ) public virtual override returns (uint256) { + require(assets <= maxWithdraw(owner), "ERC20TokenizedVault: withdraw more than max"); + + uint256 shares = previewWithdraw(assets); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return shares; + } + + /** @dev See {IERC4262-redeem} */ + function redeem( + uint256 shares, + address receiver, + address owner + ) public virtual override returns (uint256) { + require(shares <= maxRedeem(owner), "ERC20TokenizedVault: redeem more than max"); + + uint256 assets = previewRedeem(shares); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return assets; + } + + /** + * @dev Internal convertion function (from assets to shares) with support for rounding direction + * + * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset + * would represent an infinite amout of shares. + */ + function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256 shares) { + uint256 supply = totalSupply(); + return + (assets == 0 || supply == 0) + ? assets.mulDiv(10**decimals(), 10**_asset.decimals(), rounding) + : assets.mulDiv(supply, totalAssets(), rounding); + } + + /** + * @dev Internal convertion function (from shares to assets) with support for rounding direction + */ + function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256 assets) { + uint256 supply = totalSupply(); + return + (supply == 0) + ? shares.mulDiv(10**_asset.decimals(), 10**decimals(), rounding) + : shares.mulDiv(totalAssets(), supply, rounding); + } + + /** + * @dev Deposit/mint common workflow + */ + function _deposit( + address caller, + address receiver, + uint256 assets, + uint256 shares + ) private { + // If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the + // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer, + // calls the vault, which is assumed not malicious. + // + // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the + // assets are transfered and before the shares are minted, which is a valid state. + // slither-disable-next-line reentrancy-no-eth + SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); + _mint(receiver, shares); + + emit Deposit(caller, receiver, assets, shares); + } + + /** + * @dev Withdraw/redeem common workflow + */ + function _withdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) private { + if (caller != owner) { + _spendAllowance(owner, caller, shares); + } + + // If _asset is ERC777, `transfer` can trigger trigger a reentrancy AFTER the transfer happens through the + // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, + // calls the vault, which is assumed not malicious. + // + // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the + // shares are burned and after the assets are transfered, which is a valid state. + _burn(owner, shares); + SafeERC20.safeTransfer(_asset, receiver, assets); + + emit Withdraw(caller, receiver, owner, assets, shares); + } + + function _isVaultCollateralized() private view returns (bool) { + return totalAssets() > 0 || totalSupply() == 0; + } +} diff -ruN token/ERC20/extensions/ERC20Votes.sol token/ERC20/extensions/ERC20Votes.sol --- token/ERC20/extensions/ERC20Votes.sol 2022-08-11 21:16:57.000000000 -0700 +++ token/ERC20/extensions/ERC20Votes.sol 2022-08-11 22:47:30.000000000 -0700 @@ -33,8 +33,8 @@ bytes32 private constant _DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - mapping(address => address) private _delegates; - mapping(address => Checkpoint[]) private _checkpoints; + mapping(address => address) public _delegates; + mapping(address => Checkpoint[]) public _checkpoints; Checkpoint[] private _totalSupplyCheckpoints; /** @@ -152,7 +152,7 @@ /** * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1). */ - function _maxSupply() internal view virtual returns (uint224) { + function _maxSupply() public view virtual returns (uint224) { //harnessed to public return type(uint224).max; } @@ -163,16 +163,16 @@ super._mint(account, amount); require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes"); - _writeCheckpoint(_totalSupplyCheckpoints, _add, amount); + _writeCheckpointAdd(_totalSupplyCheckpoints, amount); // HARNESS: new version without pointer } /** * @dev Snapshots the totalSupply after it has been decreased. */ - function _burn(address account, uint256 amount) internal virtual override { + function _burn(address account, uint256 amount) public virtual override { // HARNESS: internal -> public (to comply with the ERC20 harness) super._burn(account, amount); - _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount); + _writeCheckpointSub(_totalSupplyCheckpoints, amount); // HARNESS: new version without pointer } /** @@ -187,7 +187,7 @@ ) internal virtual override { super._afterTokenTransfer(from, to, amount); - _moveVotingPower(delegates(from), delegates(to), amount); + _moveVotingPower(delegates(from), delegates(to), amount); } /** @@ -195,7 +195,7 @@ * * Emits events {DelegateChanged} and {DelegateVotesChanged}. */ - function _delegate(address delegator, address delegatee) internal virtual { + function _delegate(address delegator, address delegatee) public virtual { // HARNESSED TO MAKE PUBLIC address currentDelegate = delegates(delegator); uint256 delegatorBalance = balanceOf(delegator); _delegates[delegator] = delegatee; @@ -212,25 +212,25 @@ ) private { if (src != dst && amount > 0) { if (src != address(0)) { - (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount); + (uint256 oldWeight, uint256 newWeight) = _writeCheckpointSub(_checkpoints[src], amount); // HARNESS: new version without pointer emit DelegateVotesChanged(src, oldWeight, newWeight); } if (dst != address(0)) { - (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount); + (uint256 oldWeight, uint256 newWeight) = _writeCheckpointAdd(_checkpoints[dst], amount); // HARNESS: new version without pointer emit DelegateVotesChanged(dst, oldWeight, newWeight); } } } - function _writeCheckpoint( + // HARNESS: split _writeCheckpoint() to two functions as a workaround for function pointers that cannot be managed by the tool + function _writeCheckpointAdd( Checkpoint[] storage ckpts, - function(uint256, uint256) view returns (uint256) op, uint256 delta ) private returns (uint256 oldWeight, uint256 newWeight) { uint256 pos = ckpts.length; oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes; - newWeight = op(oldWeight, delta); + newWeight = _add(oldWeight, delta); if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) { ckpts[pos - 1].votes = SafeCast.toUint224(newWeight); @@ -239,6 +239,39 @@ } } + function _writeCheckpointSub( + Checkpoint[] storage ckpts, + uint256 delta + ) private returns (uint256 oldWeight, uint256 newWeight) { + uint256 pos = ckpts.length; + oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes; + newWeight = _subtract(oldWeight, delta); + + if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) { + ckpts[pos - 1].votes = SafeCast.toUint224(newWeight); + } else { + ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)})); + } + } + + // backup of original function + // + // function _writeCheckpoint( + // Checkpoint[] storage ckpts, + // function(uint256, uint256) view returns (uint256) op, + // uint256 delta + // ) private returns (uint256 oldWeight, uint256 newWeight) { + // uint256 pos = ckpts.length; + // oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes; + // newWeight = op(oldWeight, delta); + // + // if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) { + // ckpts[pos - 1].votes = SafeCast.toUint224(newWeight); + // } else { + // ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)})); + // } + // } + function _add(uint256 a, uint256 b) private pure returns (uint256) { return a + b; } diff -ruN token/ERC20/extensions/ERC20Wrapper.sol token/ERC20/extensions/ERC20Wrapper.sol --- token/ERC20/extensions/ERC20Wrapper.sol 2022-08-11 21:28:00.000000000 -0700 +++ token/ERC20/extensions/ERC20Wrapper.sol 2022-08-11 21:29:19.000000000 -0700 @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/extensions/ERC20Wrapper.sol) +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Wrapper.sol) pragma solidity ^0.8.0; @@ -23,17 +23,6 @@ } /** - * @dev See {ERC20-decimals}. - */ - function decimals() public view virtual override returns (uint8) { - try IERC20Metadata(address(underlying)).decimals() returns (uint8 value) { - return value; - } catch { - return super.decimals(); - } - } - - /** * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens. */ function depositFor(address account, uint256 amount) public virtual returns (bool) { @@ -55,7 +44,7 @@ * @dev Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake. Internal * function that can be exposed with access control if desired. */ - function _recover(address account) internal virtual returns (uint256) { + function _recover(address account) public virtual returns (uint256) { // HARNESS: internal -> public uint256 value = underlying.balanceOf(address(this)) - totalSupply(); _mint(account, value); return value; diff -ruN token/ERC20/extensions/ERC4626.sol token/ERC20/extensions/ERC4626.sol --- token/ERC20/extensions/ERC4626.sol 2022-08-11 21:28:00.000000000 -0700 +++ token/ERC20/extensions/ERC4626.sol 1969-12-31 16:00:00.000000000 -0800 @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "../ERC20.sol"; -import "../utils/SafeERC20.sol"; -import "../../../interfaces/IERC4626.sol"; -import "../../../utils/math/Math.sol"; - -/** - * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in - * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626]. - * - * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for - * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends - * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this - * contract and not the "assets" token which is an independent contract. - * - * _Available since v4.7._ - */ -abstract contract ERC4626 is ERC20, IERC4626 { - using Math for uint256; - - IERC20Metadata private immutable _asset; - - /** - * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777). - */ - constructor(IERC20Metadata asset_) { - _asset = asset_; - } - - /** @dev See {IERC4262-asset} */ - function asset() public view virtual override returns (address) { - return address(_asset); - } - - /** @dev See {IERC4262-totalAssets} */ - function totalAssets() public view virtual override returns (uint256) { - return _asset.balanceOf(address(this)); - } - - /** @dev See {IERC4262-convertToShares} */ - function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) { - return _convertToShares(assets, Math.Rounding.Down); - } - - /** @dev See {IERC4262-convertToAssets} */ - function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) { - return _convertToAssets(shares, Math.Rounding.Down); - } - - /** @dev See {IERC4262-maxDeposit} */ - function maxDeposit(address) public view virtual override returns (uint256) { - return _isVaultCollateralized() ? type(uint256).max : 0; - } - - /** @dev See {IERC4262-maxMint} */ - function maxMint(address) public view virtual override returns (uint256) { - return type(uint256).max; - } - - /** @dev See {IERC4262-maxWithdraw} */ - function maxWithdraw(address owner) public view virtual override returns (uint256) { - return _convertToAssets(balanceOf(owner), Math.Rounding.Down); - } - - /** @dev See {IERC4262-maxRedeem} */ - function maxRedeem(address owner) public view virtual override returns (uint256) { - return balanceOf(owner); - } - - /** @dev See {IERC4262-previewDeposit} */ - function previewDeposit(uint256 assets) public view virtual override returns (uint256) { - return _convertToShares(assets, Math.Rounding.Down); - } - - /** @dev See {IERC4262-previewMint} */ - function previewMint(uint256 shares) public view virtual override returns (uint256) { - return _convertToAssets(shares, Math.Rounding.Up); - } - - /** @dev See {IERC4262-previewWithdraw} */ - function previewWithdraw(uint256 assets) public view virtual override returns (uint256) { - return _convertToShares(assets, Math.Rounding.Up); - } - - /** @dev See {IERC4262-previewRedeem} */ - function previewRedeem(uint256 shares) public view virtual override returns (uint256) { - return _convertToAssets(shares, Math.Rounding.Down); - } - - /** @dev See {IERC4262-deposit} */ - function deposit(uint256 assets, address receiver) public virtual override returns (uint256) { - require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max"); - - uint256 shares = previewDeposit(assets); - _deposit(_msgSender(), receiver, assets, shares); - - return shares; - } - - /** @dev See {IERC4262-mint} */ - function mint(uint256 shares, address receiver) public virtual override returns (uint256) { - require(shares <= maxMint(receiver), "ERC4626: mint more than max"); - - uint256 assets = previewMint(shares); - _deposit(_msgSender(), receiver, assets, shares); - - return assets; - } - - /** @dev See {IERC4262-withdraw} */ - function withdraw( - uint256 assets, - address receiver, - address owner - ) public virtual override returns (uint256) { - require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max"); - - uint256 shares = previewWithdraw(assets); - _withdraw(_msgSender(), receiver, owner, assets, shares); - - return shares; - } - - /** @dev See {IERC4262-redeem} */ - function redeem( - uint256 shares, - address receiver, - address owner - ) public virtual override returns (uint256) { - require(shares <= maxRedeem(owner), "ERC4626: redeem more than max"); - - uint256 assets = previewRedeem(shares); - _withdraw(_msgSender(), receiver, owner, assets, shares); - - return assets; - } - - /** - * @dev Internal convertion function (from assets to shares) with support for rounding direction - * - * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset - * would represent an infinite amout of shares. - */ - function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256 shares) { - uint256 supply = totalSupply(); - return - (assets == 0 || supply == 0) - ? assets.mulDiv(10**decimals(), 10**_asset.decimals(), rounding) - : assets.mulDiv(supply, totalAssets(), rounding); - } - - /** - * @dev Internal convertion function (from shares to assets) with support for rounding direction - */ - function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256 assets) { - uint256 supply = totalSupply(); - return - (supply == 0) - ? shares.mulDiv(10**_asset.decimals(), 10**decimals(), rounding) - : shares.mulDiv(totalAssets(), supply, rounding); - } - - /** - * @dev Deposit/mint common workflow - */ - function _deposit( - address caller, - address receiver, - uint256 assets, - uint256 shares - ) private { - // If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the - // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer, - // calls the vault, which is assumed not malicious. - // - // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the - // assets are transfered and before the shares are minted, which is a valid state. - // slither-disable-next-line reentrancy-no-eth - SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); - _mint(receiver, shares); - - emit Deposit(caller, receiver, assets, shares); - } - - /** - * @dev Withdraw/redeem common workflow - */ - function _withdraw( - address caller, - address receiver, - address owner, - uint256 assets, - uint256 shares - ) private { - if (caller != owner) { - _spendAllowance(owner, caller, shares); - } - - // If _asset is ERC777, `transfer` can trigger trigger a reentrancy AFTER the transfer happens through the - // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, - // calls the vault, which is assumed not malicious. - // - // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the - // shares are burned and after the assets are transfered, which is a valid state. - _burn(owner, shares); - SafeERC20.safeTransfer(_asset, receiver, assets); - - emit Withdraw(caller, receiver, owner, assets, shares); - } - - function _isVaultCollateralized() private view returns (bool) { - return totalAssets() > 0 || totalSupply() == 0; - } -} diff -ruN token/ERC20/utils/SafeERC20.sol token/ERC20/utils/SafeERC20.sol --- token/ERC20/utils/SafeERC20.sol 2022-08-11 21:28:00.000000000 -0700 +++ token/ERC20/utils/SafeERC20.sol 2022-08-11 21:28:36.000000000 -0700 @@ -4,7 +4,6 @@ pragma solidity ^0.8.0; import "../IERC20.sol"; -import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** @@ -80,22 +79,6 @@ } } - function safePermit( - IERC20Permit token, - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) internal { - uint256 nonceBefore = token.nonces(owner); - token.permit(owner, spender, value, deadline, v, r, s); - uint256 nonceAfter = token.nonces(owner); - require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); - } - /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). diff -ruN token/ERC721/extensions/draft-ERC721Votes.sol token/ERC721/extensions/draft-ERC721Votes.sol --- token/ERC721/extensions/draft-ERC721Votes.sol 2022-08-11 21:28:00.000000000 -0700 +++ token/ERC721/extensions/draft-ERC721Votes.sol 2022-08-11 21:28:36.000000000 -0700 @@ -34,7 +34,7 @@ /** * @dev Returns the balance of `account`. */ - function _getVotingUnits(address account) internal view virtual override returns (uint256) { + function _getVotingUnits(address account) public view virtual override returns (uint256) { return balanceOf(account); } } diff -ruN utils/Address.sol utils/Address.sol --- utils/Address.sol 2022-08-11 21:28:00.000000000 -0700 +++ utils/Address.sol 2022-08-11 21:28:36.000000000 -0700 @@ -131,6 +131,7 @@ uint256 value, string memory errorMessage ) internal returns (bytes memory) { + return ""; // external calls havoc require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); diff -ruN utils/math/Math.sol utils/math/Math.sol --- utils/math/Math.sol 2022-08-11 21:28:00.000000000 -0700 +++ utils/math/Math.sol 2022-08-11 21:28:36.000000000 -0700 @@ -149,78 +149,4 @@ } return result; } - - /** - * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down. - * - * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). - */ - function sqrt(uint256 a) internal pure returns (uint256) { - if (a == 0) { - return 0; - } - - // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. - // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have - // `msb(a) <= a < 2*msb(a)`. - // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`. - // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`. - // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a - // good first aproximation of `sqrt(a)` with at least 1 correct bit. - uint256 result = 1; - uint256 x = a; - if (x >> 128 > 0) { - x >>= 128; - result <<= 64; - } - if (x >> 64 > 0) { - x >>= 64; - result <<= 32; - } - if (x >> 32 > 0) { - x >>= 32; - result <<= 16; - } - if (x >> 16 > 0) { - x >>= 16; - result <<= 8; - } - if (x >> 8 > 0) { - x >>= 8; - result <<= 4; - } - if (x >> 4 > 0) { - x >>= 4; - result <<= 2; - } - if (x >> 2 > 0) { - result <<= 1; - } - - // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, - // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at - // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision - // into the expected uint128 result. - unchecked { - result = (result + a / result) >> 1; - result = (result + a / result) >> 1; - result = (result + a / result) >> 1; - result = (result + a / result) >> 1; - result = (result + a / result) >> 1; - result = (result + a / result) >> 1; - result = (result + a / result) >> 1; - return min(result, a / result); - } - } - - /** - * @notice Calculates sqrt(a), following the selected rounding direction. - */ - function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { - uint256 result = sqrt(a); - if (rounding == Rounding.Up && result * result < a) { - result += 1; - } - return result; - } }