`CrossCurrencyfCashVault` Cannot Settle Its Assets In Pieces
The `CrossCurrencyfCashVault` vault cannot settle its assets in pieces. Thus, it might cause the vault to incur unnecessary slippage.\\nThe settle vault function is designed in a manner where its assets can be settled in pieces. Therefore, the `settleVault` function accepts a `strategyTokens` or `strategyTokensToRedeem` parameter to allow the caller to specify the number of strategy tokens to be settled.\\nThe reason as mentioned in Notional's walkthrough video (Refer to the explanation at 15.50min mark) is that in some cases the caller might want to break down into multiple transactions due to massive slippage.\\nFor instance, the vault might utilize a 2 day settlement period to allow the vault to settle its assets in pieces so that it can avoid unnecessary transaction costs associated with converting all its assets back to USDC in a single transaction.\\n```\\nFile: CrossCurrencyfCashVault.sol\\n    /**\\n     * @notice During settlement all of the fCash balance in the lend currency will be redeemed to the\\n     * underlying token and traded back to the borrow currency. All of the borrow currency will be deposited\\n     * into the Notional contract as asset tokens and held for accounts to withdraw. Settlement can only\\n     * be called after maturity.\\n     * @param maturity the maturity to settle\\n     * @param settlementTrade details for the settlement trade\\n     */\\n    function settleVault(uint256 maturity, uint256 strategyTokens, bytes calldata settlementTrade) external {\\n        require(maturity <= block.timestamp, "Cannot Settle");\\n        VaultState memory vaultState = NOTIONAL.getVaultState(address(this), maturity);\\n        require(vaultState.isSettled == false);\\n        require(vaultState.totalStrategyTokens >= strategyTokens);\\n\\n        RedeemParams memory params = abi.decode(settlementTrade, (RedeemParams));\\n    \\n        // The only way for underlying value to be negative would be if the vault has somehow ended up with a borrowing\\n        // position in the lend underlying currency. This is explicitly prevented during redemption.\\n        uint256 underlyingValue = convertStrategyToUnderlying(\\n            address(0), vaultState.totalStrategyTokens, maturity\\n        ).toUint();\\n\\n        // Authenticate the minimum purchase amount, all tokens will be sold given this slippage limit.\\n        uint256 minAllowedPurchaseAmount = (underlyingValue * settlementSlippageLimit) / SETTLEMENT_SLIPPAGE_PRECISION;\\n        require(params.minPurchaseAmount >= minAllowedPurchaseAmount, "Purchase Limit");\\n\\n        NOTIONAL.redeemStrategyTokensToCash(maturity, strategyTokens, settlementTrade);\\n\\n        // If there are no more strategy tokens left, then mark the vault as settled\\n        vaultState = NOTIONAL.getVaultState(address(this), maturity);\\n        if (vaultState.totalStrategyTokens == 0) {\\n            NOTIONAL.settleVault(address(this), maturity);\\n        }\\n    }\\n```\\n\\nDuring vault settlement, the `CrossCurrencyfCashVault._redeemFromNotional` function will be called, and the code in lines 252-262 will be executed. However, it was observed that the `strategyTokens` parameter is ignored, and the vault will forcefully settle all the strategy tokens in one go. As such, there is no way for the caller to break down the settle vault transaction into multiple transactions.\\n```\\nFile: CrossCurrencyfCashVault.sol\\n    function _redeemFromNotional(\\n        address account,\\n        uint256 strategyTokens,\\n        uint256 maturity,\\n        bytes calldata data\\n    ) internal override returns (uint256 borrowedCurrencyAmount) {\\n        uint256 balanceBefore = LEND_UNDERLYING_TOKEN.balanceOf(address(this));\\n        RedeemParams memory params = abi.decode(data, (RedeemParams));\\n\\n        if (maturity <= block.timestamp) {\\n            // Only allow the vault to redeem past maturity to settle all positions\\n            require(account == address(this));\\n            NOTIONAL.settleAccount(address(this));\\n            (int256 cashBalance, /* */, /* */) = NOTIONAL.getAccountBalance(LEND_CURRENCY_ID, address(this));\\n\\n            // It should never be possible that this contract has a negative cash balance\\n            require(0 <= cashBalance && cashBalance <= int256(uint256(type(uint88).max)));\\n\\n            // Withdraws all cash to underlying\\n            NOTIONAL.withdraw(LEND_CURRENCY_ID, uint88(uint256(cashBalance)), true);\\n        } else {\\n            // Sells fCash on Notional AMM (via borrowing)\\n            BalanceActionWithTrades[] memory action = _encodeBorrowTrade(\\n                maturity,\\n                strategyTokens,\\n                params.maxBorrowRate\\n            );\\n            NOTIONAL.batchBalanceAndTradeAction(address(this), action);\\n\\n            // Check that we have not somehow borrowed into a negative fCash position, vault borrows\\n            // are not included in account context\\n            AccountContext memory accountContext = NOTIONAL.getAccountContext(address(this));\\n            require(accountContext.hasDebt == 0x00);\\n        }\\n\\n        uint256 balanceAfter = LEND_UNDERLYING_TOKEN.balanceOf(address(this));\\n        \\n        // Trade back to borrow currency for repayment\\n        Trade memory trade = Trade({\\n            tradeType: TradeType.EXACT_IN_SINGLE,\\n            sellToken: address(LEND_UNDERLYING_TOKEN),\\n            buyToken: address(_underlyingToken()),\\n            amount: balanceAfter - balanceBefore,\\n            limit: params.minPurchaseAmount,\\n            deadline: block.timestamp,\\n            exchangeData: params.exchangeData\\n        });\\n\\n        (/* */, borrowedCurrencyAmount) = _executeTrade(params.dexId, trade);\\n    }\\n```\\n
It is recommended to update the `CrossCurrencyfCashVault._redeemFromNotional` function to allow the vault to be settled in multiple transactions.
The vault might incur unnecessary slippage during settlement as the settlement cannot be broken into multiple transactions.
```\\nFile: CrossCurrencyfCashVault.sol\\n    /**\\n     * @notice During settlement all of the fCash balance in the lend currency will be redeemed to the\\n     * underlying token and traded back to the borrow currency. All of the borrow currency will be deposited\\n     * into the Notional contract as asset tokens and held for accounts to withdraw. Settlement can only\\n     * be called after maturity.\\n     * @param maturity the maturity to settle\\n     * @param settlementTrade details for the settlement trade\\n     */\\n    function settleVault(uint256 maturity, uint256 strategyTokens, bytes calldata settlementTrade) external {\\n        require(maturity <= block.timestamp, "Cannot Settle");\\n        VaultState memory vaultState = NOTIONAL.getVaultState(address(this), maturity);\\n        require(vaultState.isSettled == false);\\n        require(vaultState.totalStrategyTokens >= strategyTokens);\\n\\n        RedeemParams memory params = abi.decode(settlementTrade, (RedeemParams));\\n    \\n        // The only way for underlying value to be negative would be if the vault has somehow ended up with a borrowing\\n        // position in the lend underlying currency. This is explicitly prevented during redemption.\\n        uint256 underlyingValue = convertStrategyToUnderlying(\\n            address(0), vaultState.totalStrategyTokens, maturity\\n        ).toUint();\\n\\n        // Authenticate the minimum purchase amount, all tokens will be sold given this slippage limit.\\n        uint256 minAllowedPurchaseAmount = (underlyingValue * settlementSlippageLimit) / SETTLEMENT_SLIPPAGE_PRECISION;\\n        require(params.minPurchaseAmount >= minAllowedPurchaseAmount, "Purchase Limit");\\n\\n        NOTIONAL.redeemStrategyTokensToCash(maturity, strategyTokens, settlementTrade);\\n\\n        // If there are no more strategy tokens left, then mark the vault as settled\\n        vaultState = NOTIONAL.getVaultState(address(this), maturity);\\n        if (vaultState.totalStrategyTokens == 0) {\\n            NOTIONAL.settleVault(address(this), maturity);\\n        }\\n    }\\n```\\n