Inherit asset decimals in ERC4626 (#3639)

This commit is contained in:
Hadrien Croubois
2022-08-26 09:53:53 +02:00
committed by GitHub
parent e45b49eab8
commit 141130db27
5 changed files with 104 additions and 8 deletions

View File

@ -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;
}
/**