contract GameeVouchersRedeemer is ERC1155TokenReceiver, Ownable, Pausable {
    using SafeMath for uint256;

    event VoucherRedeemedSingle(address _from, uint256 _id, uint256 _value, uint256 _gameeAmount);
    event VoucherRedeemedBatch(address _from, uint256[] _ids, uint256[] _values, uint256 _gameeAmount);

    IERC1155InventoryBurnable private gameeVouchersContract;
    IERC20Transferrable private gameeContract;

    /**
     * Constructor
     * @dev Reverts if one of the argument addresses is zero.
     * @param gameeVouchersContract_ IERC1155InventoryBurnable the address of GameeVoucher contract
     * @param gameeContract_ IERC20Transferrable the address of GAMEE contract
     */
    constructor(address gameeVouchersContract_, address gameeContract_) public {
        require(gameeVouchersContract_ != address(0) && gameeContract_ != address(0), "Redeemer: zero address");
        gameeVouchersContract = IERC1155InventoryBurnable(gameeVouchersContract_);
        gameeContract = IERC20Transferrable(gameeContract_);
    }

    /**
     * @notice ERC1155 single transfer receiver which redeem a voucher.
     * @dev Reverts if the transfer was not operated through `gameeVouchersContract`.
     * @dev Reverts if the `id` is zero.
     * @dev Reverts if the `value` is zero.
     * @dev Emits an ERC1155 TransferSingle event for the redeemed voucher.
     * @dev Emits an ERC20 Transfer event for the GAMME transfer operation.
     * @dev Emits a VoucherRedeemedSingle event.
     * @param /operator the address which initiated the transfer (i.e. msg.sender).
     * @param from the address which previously owned the voucher.
     * @param id the voucher id.
     * @param value the voucher value.
     * @param /data additional data with no specified format.
     * @return bytes4 `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`.
     */
    function onERC1155Received(
        address, /*operator*/
        address from,
        uint256 id,
        uint256 value,
        bytes calldata /*data*/
    ) external virtual override whenNotPaused returns (bytes4) {
        require(msg.sender == address(gameeVouchersContract), "Redeemer: wrong inventory");
        require(id != 0, "Redeemer: invalid voucher id");
        
        gameeVouchersContract.burnFrom(address(this), id, value);
        uint256 gameeAmount = id.mul(value);
        gameeContract.transfer(from, gameeAmount);

        emit VoucherRedeemedSingle(from, id, value, gameeAmount);

        return _ERC1155_RECEIVED;
    }

    /**
     * @notice ERC1155 batch transfer receiver which redeem a batch of vouchers.
     * @dev Reverts if the transfer was not operated through `gameeVouchersContract`.
     * @dev Reverts if `ids` is an empty array.
     * @dev Reverts if `values` is an empty array.
     * @dev Reverts if `ids` and `values` have different lengths.
     * @dev Emits an ERC1155 TransferBatch event for the redeemed vouchers.
     * @dev Emits an ERC20 Transfer event for the GAMME transfer operation.
     * @dev Emits a VoucherRedeemedBatch event.
     * @param /operator the address which initiated the transfer (i.e. msg.sender).
     * @param from the address which previously owned the voucher.
     * @param ids the vouchers ids.
     * @param values the vouchers values.
     * @param /data additional data with no specified format.
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`.
     */
    function onERC1155BatchReceived(
        address, /*operator*/
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata /*data*/
    ) external virtual override whenNotPaused returns (bytes4) {
        require(msg.sender == address(gameeVouchersContract), "Redeemer: wrong inventory");
        
        uint256 gameeAmount = 0;
        for (uint256 i = 0; i < ids.length; i++) {
            gameeAmount = gameeAmount.add(ids[i].mul(values[i]));
        }
        gameeVouchersContract.batchBurnFrom(address(this), ids, values);
        gameeContract.transfer(from, gameeAmount);

        emit VoucherRedeemedBatch(from, ids, values, gameeAmount);

        return _ERC1155_BATCH_RECEIVED;
    }

    /**
     * @notice Withdraw fungible token GAMEE allocated on this contract.
     * @dev Reverts if called by any account other than the owner.
     * @dev Reverts if amount is zero.
     * @dev Emits an ERC20 Transfer event for the GAMME transfer operation.
     * @param amount the total amount to withdraw.
     */
    function withdraw(uint256 amount) external onlyOwner {
        require(amount != 0, "Redeemer: invalid amount");
        gameeContract.transfer(msg.sender, amount);
    }
}
/**
 * @title GameeVouchersRedeemer
 * This contract is used to receive a voucher and provide an amount of GAMEE token.
 * As part of the process, it is also used to burn the voucher up after a successful GAMEE transfer.
 */
function withdraw(uint256 amount) external onlyOwner {
    require(amount != 0, "Redeemer: invalid amount");
    gameeContract.transfer(msg.sender, amount);
}

/**
 * @notice Withdraw fungible token GAMEE allocated on this contract.
 * @dev Reverts if called by any account other than the owner.
 * @dev Reverts if amount is zero.
 * @dev Emits an ERC20 Transfer event for the GAMME transfer operation.
 * @param amount the total amount to withdraw.
 */