function _withdraw(
	address to,
	uint256 amount
) internal override nonReentrant {
	uint256 available = _currentBalance();
	require(available >= amount, "CompoundStrategy: amount not valid");

	uint256 queued = wrappedNative.balanceOf(address(this));
	if (amount > queued) {
		uint256 pricePerShare = cToken.exchangeRateStored();
		uint256 toWithdraw = (((amount - queued) * (10 ** 18)) /
			pricePerShare);

		cToken.redeem(toWithdraw);
/**
 * @notice Sender redeems cTokens in exchange for the underlying asset
 * @dev Accrues interest whether or not the operation succeeds, unless reverted
 * @param redeemTokens The number of cTokens to redeem into underlying
 * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
 */
function redeem(uint redeemTokens) external returns (uint) {
	return redeemInternal(redeemTokens);
}
/**
 * @notice Sender redeems cTokens in exchange for the underlying asset
 * @dev Accrues interest whether or not the operation succeeds, unless reverted
 * @param redeemTokens The number of cTokens to redeem into underlying
 * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
 */
function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) {
	uint error = accrueInterest();
	if (error != uint(Error.NO_ERROR)) {
		// accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
		return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
	}
	// redeemFresh emits redeem-specific logs on errors, so we don't need to
	return redeemFresh(msg.sender, redeemTokens, 0);
}
function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {

	...

	/* exchangeRate = invoke Exchange Rate Stored() */
	(vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();

	...
	
	/* If redeemTokensIn > 0: */
	if (redeemTokensIn > 0) {
		/*
		 * We calculate the exchange rate and the amount of underlying to be redeemed:
		 *  redeemTokens = redeemTokensIn
		 *  redeemAmount = redeemTokensIn x exchangeRateCurrent
		 */
		vars.redeemTokens = redeemTokensIn;
	
		(vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);
		if (vars.mathErr != MathError.NO_ERROR) {
			return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));
		}

	...

	vars.err = doTransferOut(redeemer, vars.redeemAmount);

	...

}
pragma solidity 0.8.19;

contract MatchCalcs {
    uint constant expScale = 1e18;
    
    struct Exp {
        uint mantissa;
    }

    function mulScalarTruncate(Exp memory a, uint scalar) pure external returns (uint) {
        return truncate(mulScalar(a, scalar));
    }

    function mulScalar(Exp memory a, uint scalar) pure internal returns (Exp memory) {
        uint256 scaledMantissa = mulUInt(a.mantissa, scalar);

        return Exp({mantissa: scaledMantissa});
    }

    function mulUInt(uint a, uint b) internal pure returns (uint) {
        if (a == 0) {
            return 0;
        }

        uint c = a * b;

        if (c / a != b) {
            return 0;
        } else {
            return c;
        }
    }

    function truncate(Exp memory exp) pure internal returns (uint) {
        // Note: We are not using careful math here as we're performing a division that cannot fail
        return exp.mantissa / expScale;
    }

    function getToWithdraw(uint256 amount, uint256 exchangeRate) pure external returns (uint) {
        return amount * (10 ** 18) / exchangeRate;
    }
}
require(
	wrappedNative.balanceOf(address(this)) >= amount,
	"CompoundStrategy: not enough"
);
