contract Helper is ERC1155Receiver{
    IFoundry immutable public foundry;
    IShareToken immutable public shareToken;
    IERC20 immutable public cash;
    address immutable public augur;


    using SafeMath for uint256;

    constructor(address _augur,IFoundry _foundry,IShareToken _shareToken,IERC20 _cash) public{
        augur = _augur;
        foundry = _foundry;
        shareToken = _shareToken;
        cash = _cash;
        _shareToken.setApprovalForAll(address(_foundry),true);
    }

    function mintWrapJoin(
        uint256[] memory _tokenIds,
        uint256[] memory _wrappingAmounts,
        uint256[] memory _getBackTokenIds,
        address _market,
        uint256 _numTicks,
        uint256 _mintAmount,
        uint256 _amountOfDAIToAdd,
        IBPool _pool,
        uint256 _poolAmountOut, 
        uint256[] memory _maxAmountsIn
    ) public {
        require(_tokenIds.length == _wrappingAmounts.length && _tokenIds.length == _maxAmountsIn.length - 1,"Invalid inputs");
        require(
            cash.transferFrom(
                msg.sender,
                address(this),
                (_mintAmount.mul(_numTicks)).add(_amountOfDAIToAdd)
            )
        );
        cash.approve(augur, _mintAmount.mul(_numTicks).add(_amountOfDAIToAdd));
        shareToken.buyCompleteSets(_market, address(this), _mintAmount);     
        for (uint256 i = 0; i < _getBackTokenIds.length; i++) {
                shareToken.safeTransferFrom(
                    address(this),
                    msg.sender,
                    _getBackTokenIds[i],
                    _mintAmount,
                    ''
                );
        }
        foundry.wrapMultipleTokens(_tokenIds,address(this),_wrappingAmounts);
        if(address(_pool) != address(0)){
            for(uint256 i=0 ; i<_tokenIds.length; i++){
                address erc20WrapperAddress = foundry.wrappers(_tokenIds[i]);
                IERC20(erc20WrapperAddress).approve(address(_pool),uint256(-1));
            }
            cash.approve(address(_pool),_amountOfDAIToAdd);

            _pool.joinPool(_poolAmountOut,_maxAmountsIn);
            _pool.transfer(msg.sender,_poolAmountOut);
        }
        for(uint256 i=0;i<_tokenIds.length;i++){
            IERC20 erc20Wrapper = IERC20(foundry.wrappers(_tokenIds[i]));
            uint256 balanceOfERC20Wrapper =erc20Wrapper.balanceOf(address(this));
            if(balanceOfERC20Wrapper != 0){
                erc20Wrapper.transfer(msg.sender,balanceOfERC20Wrapper);
            }
        }
        uint256 balanceOfCash = cash.balanceOf(address(this));
        if(balanceOfCash != 0){
                cash.transfer(msg.sender,balanceOfCash);
        }
    }
    function exitUnWrapRedeem(IBPool _pool,uint256 _poolAmountIn, uint256[] memory _minAmountsOut,uint256[] memory _tokenIds,address _market,uint256[] memory _outcomes,bytes32 _fingerprint) public{
       require(_tokenIds.length == _minAmountsOut.length - 1,"Invalid inputs");
       require(
            _pool.transferFrom(
                msg.sender,
                address(this),
               _poolAmountIn
            )
        );
        _pool.exitPool(_poolAmountIn,_minAmountsOut);


        //transfer DAI back to the user
        uint256 balanceOfCash = cash.balanceOf(address(this));
        if(balanceOfCash != 0){
                cash.transfer(msg.sender,balanceOfCash);
        }

        for(uint256 i = 0; i <_tokenIds.length;i++){
            IERC20Wrapper erc20Wrapper = IERC20Wrapper(foundry.wrappers(_tokenIds[i]));
            uint256 balanceOfERC20Wrapper = erc20Wrapper.balanceOf(address(this));
            if(balanceOfERC20Wrapper != 0){
                erc20Wrapper.unWrapTokens(address(this),balanceOfERC20Wrapper);
                shareToken.safeTransferFrom(
                        address(this),
                        msg.sender,
                        _tokenIds[i],
                        balanceOfERC20Wrapper,
                        ''
                );
            }
        }
        uint256 amountOfcompleteShares = shareToken.lowestBalanceOfMarketOutcomes(_market,_outcomes,msg.sender);
        shareToken.sellCompleteSets(_market,msg.sender,msg.sender,amountOfcompleteShares,_fingerprint);

    }
    

  /**
        @dev Handles the receipt of a single ERC1155 token type. This function is
        called at the end of a `safeTransferFrom` after the balance has been updated.
        To accept the transfer, this must return
        `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
        (i.e. 0xf23a6e61, or its own function selector).
        @param operator The address which initiated the transfer (i.e. _msgSender())
        @param from The address which previously owned the token
        @param id The ID of the token being transferred
        @param value The amount of tokens being transferred
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
    */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external override pure returns (bytes4) {
        return (
            bytes4(
                keccak256(
                    'onERC1155Received(address,address,uint256,uint256,bytes)'
                )
            )
        );
    }

    /**
        @dev Handles the receipt of a multiple ERC1155 token types. This function
        is called at the end of a `safeBatchTransferFrom` after the balances have
        been updated. To accept the transfer(s), this must return
        `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
        (i.e. 0xbc197c81, or its own function selector).
        @param operator The address which initiated the batch transfer (i.e. _msgSender())
        @param from The address which previously owned the token
        @param ids An array containing ids of each token being transferred (order and length must match values array)
        @param values An array containing amounts of each token being transferred (order and length must match ids array)
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
    */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external override pure returns (bytes4) {
        return
            bytes4(
                keccak256(
                    'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)'
                )
            );
    }
}
function onERC1155Received(
    address operator,
    address from,
    uint256 id,
    uint256 value,
    bytes calldata data
) external override pure returns (bytes4) {
    return (
        bytes4(
            keccak256(
                'onERC1155Received(address,address,uint256,uint256,bytes)'
            )
        )
    );
}

/**
 @dev Handles the receipt of a single ERC1155 token type. This function is
 called at the end of a `safeTransferFrom` after the balance has been updated.
 To accept the transfer, this must return
 `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
 (i.e. 0xf23a6e61, or its own function selector).
 @param operator The address which initiated the transfer (i.e. _msgSender())
 @param from The address which previously owned the token
 @param id The ID of the token being transferred
 @param value The amount of tokens being transferred
 @param data Additional data with no specified format
 @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
 */