|
@@ -10,38 +10,6 @@ diff -ruN access/AccessControl.sol access/AccessControl.sol
|
|
|
_checkRole(role, _msgSender());
|
|
|
}
|
|
|
|
|
|
-diff -ruN access/Ownable.sol access/Ownable.sol
|
|
|
---- access/Ownable.sol 2022-09-09 10:15:55.887175731 +0200
|
|
|
-+++ access/Ownable.sol 2022-09-20 14:34:08.629602185 +0200
|
|
|
-@@ -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 .gitignore .gitignore
|
|
|
--- .gitignore 1970-01-01 01:00:00.000000000 +0100
|
|
|
+++ .gitignore 2022-09-20 14:34:08.626268788 +0200
|
|
@@ -177,59 +145,6 @@ diff -ruN governance/utils/Votes.sol governance/utils/Votes.sol
|
|
|
- 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-09-20 11:16:48.456850883 +0200
|
|
|
-+++ metatx/MinimalForwarder.sol 2022-09-20 14:34:08.632935582 +0200
|
|
|
-@@ -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 1970-01-01 01:00:00.000000000 +0100
|
|
|
-+++ mocks/ERC20TokenizedVaultMock.sol 2022-09-20 14:34:08.632935582 +0200
|
|
|
-@@ -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/MathMock.sol mocks/MathMock.sol
|
|
|
---- mocks/MathMock.sol 2022-09-20 14:24:58.013407601 +0200
|
|
|
-+++ mocks/MathMock.sol 2022-09-20 14:34:24.803248911 +0200
|
|
|
-@@ -45,4 +45,8 @@
|
|
|
- function log256(uint256 a, Math.Rounding direction) public pure returns (uint256) {
|
|
|
- return Math.log256(a, 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-09-20 14:24:58.013407601 +0200
|
|
|
+++ mocks/SafeERC20Helper.sol 2022-09-20 15:09:17.135329080 +0200
|
|
@@ -340,89 +255,6 @@ diff -ruN mocks/SafeERC20Helper.sol mocks/SafeERC20Helper.sol
|
|
|
function setAllowance(uint256 allowance_) public {
|
|
|
ERC20ReturnTrueMock(address(_token)).setAllowance(allowance_);
|
|
|
}
|
|
|
-diff -ruN proxy/beacon/BeaconProxy.sol proxy/beacon/BeaconProxy.sol
|
|
|
---- proxy/beacon/BeaconProxy.sol 2022-09-09 10:15:55.890509851 +0200
|
|
|
-+++ proxy/beacon/BeaconProxy.sol 2022-09-20 14:34:24.806582310 +0200
|
|
|
-@@ -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/Clones.sol proxy/Clones.sol
|
|
|
---- proxy/Clones.sol 2022-09-20 14:24:58.013407601 +0200
|
|
|
-+++ proxy/Clones.sol 2022-09-20 14:59:00.690035663 +0200
|
|
|
-@@ -27,10 +27,10 @@
|
|
|
- assembly {
|
|
|
- // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
|
|
|
- // of the `implementation` address with the bytecode before the address.
|
|
|
-- mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
|
|
|
-+ mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x602d8060093d393df3363d3d373d3d3d363d73000000))
|
|
|
- // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
|
|
|
- mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
|
|
|
-- instance := create(0, 0x09, 0x37)
|
|
|
-+ instance := create(0, 0x0A, 0x36)
|
|
|
- }
|
|
|
- require(instance != address(0), "ERC1167: create failed");
|
|
|
- }
|
|
|
-@@ -47,10 +47,10 @@
|
|
|
- assembly {
|
|
|
- // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
|
|
|
- // of the `implementation` address with the bytecode before the address.
|
|
|
-- mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
|
|
|
-+ mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x602d8060093d393df3363d3d373d3d3d363d73000000))
|
|
|
- // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
|
|
|
- mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
|
|
|
-- instance := create2(0, 0x09, 0x37, salt)
|
|
|
-+ instance := create2(0, 0x0A, 0x36, salt)
|
|
|
- }
|
|
|
- require(instance != address(0), "ERC1167: create2 failed");
|
|
|
- }
|
|
|
-@@ -66,13 +66,13 @@
|
|
|
- /// @solidity memory-safe-assembly
|
|
|
- assembly {
|
|
|
- let ptr := mload(0x40)
|
|
|
-- mstore(add(ptr, 0x38), deployer)
|
|
|
-- mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
|
|
|
-- mstore(add(ptr, 0x14), implementation)
|
|
|
-- mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
|
|
|
-- mstore(add(ptr, 0x58), salt)
|
|
|
-- mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
|
|
|
-- predicted := keccak256(add(ptr, 0x43), 0x55)
|
|
|
-+ mstore(add(ptr, 0x37), deployer)
|
|
|
-+ mstore(add(ptr, 0x23), 0x5af43d82803e903d91602b57fd5bf3ff)
|
|
|
-+ mstore(add(ptr, 0x13), implementation)
|
|
|
-+ mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d73)
|
|
|
-+ mstore(add(ptr, 0x57), salt)
|
|
|
-+ mstore(add(ptr, 0x77), keccak256(add(ptr, 0x0b), 0x36))
|
|
|
-+ predicted := keccak256(add(ptr, 0x44), 0x55)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-diff -ruN proxy/ERC1967/ERC1967Proxy.sol proxy/ERC1967/ERC1967Proxy.sol
|
|
|
---- proxy/ERC1967/ERC1967Proxy.sol 2022-09-09 10:15:55.890509851 +0200
|
|
|
-+++ proxy/ERC1967/ERC1967Proxy.sol 2022-09-20 14:34:24.806582310 +0200
|
|
|
-@@ -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/transparent/TransparentUpgradeableProxy.sol proxy/transparent/TransparentUpgradeableProxy.sol
|
|
|
---- proxy/transparent/TransparentUpgradeableProxy.sol 2022-09-09 10:15:55.890509851 +0200
|
|
|
-+++ proxy/transparent/TransparentUpgradeableProxy.sol 2022-09-20 14:34:24.806582310 +0200
|
|
|
-@@ -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-09-20 11:16:48.456850883 +0200
|
|
|
+++ proxy/utils/Initializable.sol 2022-09-20 14:34:24.806582310 +0200
|
|
@@ -441,63 +273,6 @@ diff -ruN proxy/utils/Initializable.sol proxy/utils/Initializable.sol
|
|
|
|
|
|
/**
|
|
|
* @dev Triggered when the contract has been initialized or reinitialized.
|
|
|
-diff -ruN security/Pausable.sol security/Pausable.sol
|
|
|
---- security/Pausable.sol 2022-09-09 10:15:55.890509851 +0200
|
|
|
-+++ security/Pausable.sol 2022-09-20 14:34:24.809915708 +0200
|
|
|
-@@ -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-09-20 11:01:10.432848512 +0200
|
|
|
+++ token/ERC1155/ERC1155.sol 2022-09-20 14:34:24.809915708 +0200
|
|
@@ -556,227 +331,6 @@ diff -ruN token/ERC20/extensions/ERC20FlashMint.sol token/ERC20/extensions/ERC20
|
|
|
/**
|
|
|
* @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 1970-01-01 01:00:00.000000000 +0100
|
|
|
-+++ token/ERC20/extensions/ERC20TokenizedVault.sol 2022-09-20 14:34:24.809915708 +0200
|
|
|
-@@ -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-09-20 14:24:58.016740934 +0200
|
|
|
+++ token/ERC20/extensions/ERC20Votes.sol 2022-09-20 15:05:11.770836991 +0200
|
|
@@ -904,31 +458,6 @@ diff -ruN token/ERC20/extensions/ERC20Votes.sol token/ERC20/extensions/ERC20Vote
|
|
|
diff -ruN token/ERC20/extensions/ERC20Wrapper.sol token/ERC20/extensions/ERC20Wrapper.sol
|
|
|
--- token/ERC20/extensions/ERC20Wrapper.sol 2022-08-31 13:44:36.381058287 +0200
|
|
|
+++ token/ERC20/extensions/ERC20Wrapper.sol 2022-09-20 14:34:24.809915708 +0200
|
|
|
-@@ -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.
|
|
@@ -938,27 +467,6 @@ diff -ruN token/ERC20/extensions/ERC20Wrapper.sol token/ERC20/extensions/ERC20Wr
|
|
|
uint256 value = underlying.balanceOf(address(this)) - totalSupply();
|
|
|
_mint(account, value);
|
|
|
return value;
|
|
|
-diff -ruN token/ERC20/README.adoc token/ERC20/README.adoc
|
|
|
---- token/ERC20/README.adoc 2022-09-20 13:34:47.024598756 +0200
|
|
|
-+++ token/ERC20/README.adoc 2022-09-20 14:34:24.809915708 +0200
|
|
|
-@@ -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/utils/SafeERC20.sol token/ERC20/utils/SafeERC20.sol
|
|
|
--- token/ERC20/utils/SafeERC20.sol 2022-09-09 10:15:55.893843970 +0200
|
|
|
+++ token/ERC20/utils/SafeERC20.sol 2022-09-20 14:34:28.259983206 +0200
|