contract WrappedERC4626YearnCRV is ApyFlowVault {
    using SafeERC20 for IERC20Metadata;
    using SafeAssetConverter for AssetConverter;

    IERC20Metadata public immutable crv;
    IERC20Metadata public immutable ycrv;
    IYearnV2Vault public immutable stycrv;
    AssetConverter public immutable assetConverter;
    ICurvePool public immutable curveYCRVpool;

    constructor(
        IERC20Metadata _crv,
        IERC20Metadata _ycrv,
        IYearnV2Vault _stycrv,
        ICurvePool _curveYCRVPool,
        AssetConverter _assetConverter,
        string memory name,
        string memory symbol
    ) ApyFlowVault(_crv) ERC20(name, symbol) {
        require(address(_crv) != address(0), "Zero address provided");
        require(address(_ycrv) != address(0), "Zero address provided");
        require(address(_stycrv) != address(0), "Zero address provided");
        require(address(_curveYCRVPool) != address(0), "Zero address provided");

        crv = _crv;
        ycrv = _ycrv;
        stycrv = _stycrv;
        curveYCRVpool = _curveYCRVPool;
        assetConverter = _assetConverter;

        crv.safeIncreaseAllowance(address(assetConverter), type(uint256).max);
        ycrv.safeIncreaseAllowance(address(assetConverter), type(uint256).max);
        ycrv.safeIncreaseAllowance(address(stycrv), type(uint256).max);
    }

    function _totalAssets() internal view override returns (uint256) {
        uint256 ycrvAmount = (stycrv.balanceOf(address(this)) *
            stycrv.pricePerShare()) / (10 ** stycrv.decimals());
        uint256 ycrvPrice = curveYCRVpool.get_dy(1, 0, 10 ** ycrv.decimals());
        return ycrvAmount * ycrvPrice / (10 ** ycrv.decimals());
    }

    function _deposit(
        uint256 assets
    ) internal override {
        if (assetConverter.previewSwap(address(crv), address(ycrv), assets) == 0) {
            // if we are going to get 0 ycrv, than we are not doing anything and just keep crv at balance
            return;
        }
        uint256 ycrvAmount = assetConverter.safeSwap(address(crv), address(ycrv), assets);
        stycrv.deposit(ycrvAmount);
    }

    function _redeem(uint256 shares) internal override returns(uint256 assets) {
        uint256 stycrvShares = shares * stycrv.balanceOf(address(this)) / totalSupply();
        if (stycrvShares == 0) return 0;
        uint256 ycrvAmount = stycrv.withdraw(stycrvShares, address(this));
        if (ycrvAmount == 0) return 0;
        assets = assetConverter.safeSwap(address(ycrv), address(crv), assets);
    }
}
[{"inputs":[{"components":[{"internalType":"contract IAavePool","name":"aavePool","type":"address"},{"internalType":"contract IAavePriceOracle","name":"aavePriceOracle","type":"address"},{"internalType":"address","name":"tokenToBorrow","type":"address"},{"internalType":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"ltv","type":"uint256"}],"internalType":"struct AaveLibrary.Data","name":"_aave","type":"tuple"},{"internalType":"contract IERC20Metadata","name":"asset_","type":"address"},{"internalType":"contract WrappedERC4626YearnCRVAave","name":"_crvVault","type":"address"},{"internalType":"contract ChainlinkPriceFeedAggregator","name":"_pricesOracle","type":"address"},{"internalType":"contract AssetConverter","name":"_assetConverter","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"aave","outputs":[{"internalType":"contract IAavePool","name":"aavePool","type":"address"},{"internalType":"contract IAavePriceOracle","name":"aavePriceOracle","type":"address"},{"internalType":"address","name":"tokenToBorrow","type":"address"},{"internalType":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"ltv","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetConverter","outputs":[{"internalType":"contract AssetConverter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crv","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crvVault","outputs":[{"internalType":"contract WrappedERC4626YearnCRVAave","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_premium","type":"uint256"},{"internalType":"address","name":"_initiator","type":"address"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricesOracle","outputs":[{"internalType":"contract ChainlinkPriceFeedAggregator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]