contract LiquidityAccess is LiquidityAccessHelper {

    event LogFlashBorrow(address[] token, uint256[] tokenAmt);
    event LogFlashPayback(address[] token, uint256[] tokenAmt, uint256[] totalAmtFee);

    /**
     * @dev Borrow Flashloan and Cast spells.
     * @param token Token Address.
     * @param amt Token Amount.
     * @param data targets & data for cast.
     */
    function flashBorrowAndCast(address token, uint amt, uint route, bytes memory data) public payable {
        AccountInterface(address(this)).enable(getInstaFlashV2Addr());

        address[] memory tokens = new address[](1);
        uint[] memory amts = new uint[](1);
        tokens[0] = token;
        amts[0] = amt;

        emit LogFlashBorrow(tokens, amts);

        InstaFlashV2Interface(getInstaFlashV2Addr()).initiateFlashLoan(tokens, amts, route, data);

        AccountInterface(address(this)).disable(getInstaFlashV2Addr());

    }

    /**
     * @dev Return token to InstaPool.
     * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
     * @param amt token amt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
     * @param getId Get token amount at this ID from `InstaMemory` Contract.
     * @param setId Set token amount at this ID in `InstaMemory` Contract.
    */
    function flashPayback(address token, uint amt, uint getId, uint setId) external payable {
        uint _amt = getUint(getId, amt);
        
        InstaFlashV2Interface instapoolContract = InstaFlashV2Interface(getInstaFlashV2Addr());
        IERC20 tokenContract = IERC20(token);

        (uint totalFeeAmt) = calculateTotalFeeAmt(instapoolContract, _amt);

        _transfer(payable(address(getInstaFlashV2Addr())), tokenContract, totalFeeAmt);

        setUint(setId, totalFeeAmt);

        address[] memory tokens = new address[](1);
        uint[] memory amts = new uint[](1);
        uint[] memory totalFeeAmts = new uint[](1);
        tokens[0] = token;
        amts[0] = amt;
        totalFeeAmts[0] = totalFeeAmt;

        emit LogFlashPayback(tokens, amts, totalFeeAmts);
    }
}
function flashPayback(address token, uint amt, uint getId, uint setId) external payable {
    uint _amt = getUint(getId, amt);
        
    InstaFlashV2Interface instapoolContract = InstaFlashV2Interface(getInstaFlashV2Addr());
    IERC20 tokenContract = IERC20(token);

    (uint totalFeeAmt) = calculateTotalFeeAmt(instapoolContract, _amt);

    _transfer(payable(address(getInstaFlashV2Addr())), tokenContract, totalFeeAmt);

    setUint(setId, totalFeeAmt);

    address[] memory tokens = new address[](1);
    uint[] memory amts = new uint[](1);
    uint[] memory totalFeeAmts = new uint[](1);
    tokens[0] = token;
    amts[0] = amt;
    totalFeeAmts[0] = totalFeeAmt;

    emit LogFlashPayback(tokens, amts, totalFeeAmts);
}

/**
 * @dev Return token to InstaPool.
 * @param token token address.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
 * @param amt token amt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
 * @param getId Get token amount at this ID from `InstaMemory` Contract.
 * @param setId Set token amount at this ID in `InstaMemory` Contract.
 */