|
@@ -26,13 +26,27 @@ import "../../../utils/math/Math.sol";
|
|
|
abstract contract ERC4626 is ERC20, IERC4626 {
|
|
|
using Math for uint256;
|
|
|
|
|
|
- IERC20Metadata private immutable _asset;
|
|
|
+ IERC20 private immutable _asset;
|
|
|
+ uint8 private immutable _decimals;
|
|
|
|
|
|
/**
|
|
|
* @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).
|
|
|
*/
|
|
|
- constructor(IERC20Metadata asset_) {
|
|
|
+ constructor(IERC20 asset_) {
|
|
|
+ uint8 decimals_;
|
|
|
+ try IERC20Metadata(address(asset_)).decimals() returns (uint8 value) {
|
|
|
+ decimals_ = value;
|
|
|
+ } catch {
|
|
|
+ decimals_ = super.decimals();
|
|
|
+ }
|
|
|
+
|
|
|
_asset = asset_;
|
|
|
+ _decimals = decimals_;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** @dev See {IERC20Metadata-decimals}. */
|
|
|
+ function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) {
|
|
|
+ return _decimals;
|
|
|
}
|
|
|
|
|
|
/** @dev See {IERC4626-asset}. */
|
|
@@ -153,19 +167,41 @@ abstract contract ERC4626 is ERC20, IERC4626 {
|
|
|
uint256 supply = totalSupply();
|
|
|
return
|
|
|
(assets == 0 || supply == 0)
|
|
|
- ? assets.mulDiv(10**decimals(), 10**_asset.decimals(), rounding)
|
|
|
+ ? _initialConvertToShares(assets, rounding)
|
|
|
: assets.mulDiv(supply, totalAssets(), rounding);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @dev Internal conversion function (from assets to shares) to apply when the vault is empty.
|
|
|
+ *
|
|
|
+ * NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it.
|
|
|
+ */
|
|
|
+ function _initialConvertToShares(
|
|
|
+ uint256 assets,
|
|
|
+ Math.Rounding /*rounding*/
|
|
|
+ ) internal view virtual returns (uint256 shares) {
|
|
|
+ return assets;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* @dev Internal conversion 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);
|
|
|
+ (supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Internal conversion function (from shares to assets) to apply when the vault is empty.
|
|
|
+ *
|
|
|
+ * NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it.
|
|
|
+ */
|
|
|
+ function _initialConvertToAssets(
|
|
|
+ uint256 shares,
|
|
|
+ Math.Rounding /*rounding*/
|
|
|
+ ) internal view virtual returns (uint256 assets) {
|
|
|
+ return shares;
|
|
|
}
|
|
|
|
|
|
/**
|