contract ProvideLiquidity is  AccessLiquidity {
    event LogDeposit(address indexed user, address indexed token, uint amount, uint cAmount);
    event LogWithdraw(address indexed user, address indexed token, uint amount, uint cAmount);

    mapping (address => mapping (address => uint)) public liquidityBalance;

    /**
     * @dev Deposit Liquidity.
     * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
     * @param amt token amount.
    */
    function deposit(address token, uint amt) external payable returns (uint _amt) {
        require(isTknAllowed[token], "token-not-listed");
        require(amt > 0 || msg.value > 0, "amt-not-valid");

        if (msg.value > 0) require(token == ethAddr, "not-eth-addr");

        address cErc20 = tknToCTkn[token];
        uint initalBal = tokenBal(cErc20);
        if (token == ethAddr) {
            _amt = msg.value;
            CETHInterface(cErc20).mint.value(_amt)();
        } else {
            _amt = amt == (uint(-1)) ? IERC20(token).balanceOf(msg.sender) : amt;
            IERC20(token).safeTransferFrom(msg.sender, address(this), _amt);
            require(CTokenInterface(cErc20).mint(_amt) == 0, "mint-failed");
        }
        uint finalBal = tokenBal(cErc20);
        uint ctokenAmt = sub(finalBal, initalBal);

        liquidityBalance[token][msg.sender] += ctokenAmt;

        emit LogDeposit(msg.sender, token, _amt, ctokenAmt);
    }

    
    /**
     * @dev Withdraw Liquidity.
     * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
     * @param amt token amount.
    */
    function withdraw(address token, uint amt) external returns (uint _amt) {
        uint _userLiq = liquidityBalance[token][msg.sender];
        require(_userLiq > 0, "nothing-to-withdraw");

        uint _cAmt;

        address ctoken = tknToCTkn[token];
        if (amt == uint(-1)) {
            uint initknBal = tokenBal(token);
            require(CTokenInterface(ctoken).redeem(_userLiq) == 0, "redeem-failed");
            uint finTknBal = tokenBal(token);
            _cAmt = _userLiq;
            delete liquidityBalance[token][msg.sender];
            _amt = sub(finTknBal, initknBal);
        } else {
            uint iniCtknBal = tokenBal(ctoken);
            require(CTokenInterface(ctoken).redeemUnderlying(amt) == 0, "redeemUnderlying-failed");
            uint finCtknBal = tokenBal(ctoken);
            _cAmt = sub(iniCtknBal, finCtknBal);
            require(_cAmt <= _userLiq, "not-enough-to-withdraw");
            liquidityBalance[token][msg.sender] -= _cAmt;
            _amt = amt;
        }
        
        _transfer(token, _amt);
       
        emit LogWithdraw(msg.sender, token, _amt, _cAmt);
    }

}
function deposit(address token, uint amt) external payable returns (uint _amt) {
    require(isTknAllowed[token], "token-not-listed");
    require(amt > 0 || msg.value > 0, "amt-not-valid");

    if (msg.value > 0) require(token == ethAddr, "not-eth-addr");

    address cErc20 = tknToCTkn[token];
    uint initalBal = tokenBal(cErc20);
    if (token == ethAddr) {
        _amt = msg.value;
        CETHInterface(cErc20).mint.value(_amt)();
    } else {
        _amt = amt == (uint(-1)) ? IERC20(token).balanceOf(msg.sender) : amt;
        IERC20(token).safeTransferFrom(msg.sender, address(this), _amt);
        require(CTokenInterface(cErc20).mint(_amt) == 0, "mint-failed");
    }
    uint finalBal = tokenBal(cErc20);
    uint ctokenAmt = sub(finalBal, initalBal);

    liquidityBalance[token][msg.sender] += ctokenAmt;

    emit LogDeposit(msg.sender, token, _amt, ctokenAmt);
}

/**
 * @dev Deposit Liquidity.
 * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
 * @param amt token amount.
 */