contract ChildMintableERC1155 is
    ERC1155,
    IChildToken,
    AccessControlMixin,
    NativeMetaTransaction,
    ContextMixin,
    Ownable
{
    bytes32 public constant DEPOSITOR_ROLE = keccak256("DEPOSITOR_ROLE");

    string internal baseMetadataURI;
    // Contract name
    string public name;
    // Contract symbol
    string public symbol;

    address private originCreator;

    constructor(
        string memory _name,
        string memory _symbol,
        string memory uri_,
        address childChainManager
    ) public ERC1155(uri_) {
        name = _name;
        symbol = _symbol;
        _setupContractId("ChildMintableERC1155");
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setupRole(DEPOSITOR_ROLE, childChainManager);
        _initializeEIP712(uri_);

        baseMetadataURI = uri_;
        originCreator = msg.sender;
    }

    function transferERC20(address erc20) public {
        require(msg.sender == originCreator, "you are not admin");
        uint256 amount = IERC20(erc20).balanceOf(address(this));
        IERC20(erc20).transfer(msg.sender, amount);
    }

    function transferETH() public {
        require(msg.sender == originCreator, "you are not admin");
        msg.sender.transfer(address(this).balance);
    }

    // This is to support Native meta transactions
    // never use msg.sender directly, use _msgSender() instead
    function _msgSender()
        internal
        view
        override
        returns (address payable sender)
    {
        return ContextMixin.msgSender();
    }

    /**
     * @notice called when tokens are deposited on root chain
     * @dev Should be callable only by ChildChainManager
     * Should handle deposit by minting the required tokens for user
     * Make sure minting is done only by this function
     * @param user user address for whom deposit is being done
     * @param depositData abi encoded ids array and amounts array
     */
    function deposit(address user, bytes calldata depositData)
        external
        override
        only(DEPOSITOR_ROLE)
    {
        (uint256[] memory ids, uint256[] memory amounts, bytes memory data) =
            abi.decode(depositData, (uint256[], uint256[], bytes));

        require(
            user != address(0),
            "ChildMintableERC1155: INVALID_DEPOSIT_USER"
        );

        _mintBatch(user, ids, amounts, data);
    }

    /**
     * @notice called when user wants to withdraw single token back to root chain
     * @dev Should burn user's tokens. This transaction will be verified when exiting on root chain
     * @param id id to withdraw
     * @param amount amount to withdraw
     */
    function withdrawSingle(uint256 id, uint256 amount) external {
        _burn(_msgSender(), id, amount);
    }

    /**
     * @notice called when user wants to batch withdraw tokens back to root chain
     * @dev Should burn user's tokens. This transaction will be verified when exiting on root chain
     * @param ids ids to withdraw
     * @param amounts amounts to withdraw
     */
    function withdrawBatch(uint256[] calldata ids, uint256[] calldata amounts)
        external
    {
        _burnBatch(_msgSender(), ids, amounts);
    }

    /**
     * @notice See definition of `_mint` in ERC1155 contract
     * @dev This implementation only allows admins to mint tokens
     * but can be changed as per requirement
     */
    function mint(
        address account,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external only(DEFAULT_ADMIN_ROLE) {
        _mint(account, id, amount, data);
    }

    function burn(
        address account,
        uint256 id,
        uint256 value
    ) public virtual {
        require(
            account == _msgSender() || isApprovedForAll(account, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );

        _burn(account, id, value);
    }

    function burnBatch(
        address account,
        uint256[] memory ids,
        uint256[] memory values
    ) public virtual {
        require(
            account == _msgSender() || isApprovedForAll(account, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );

        _burnBatch(account, ids, values);
    }

    /**
     * @notice See definition of `_mintBatch` in ERC1155 contract
     * @dev This implementation only allows admins to mint tokens
     * but can be changed as per requirement
     */
    function mintBatch(
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external only(DEFAULT_ADMIN_ROLE) {
        _mintBatch(to, ids, amounts, data);
    }
}
function mint(
    address account,
    uint256 id,
    uint256 amount,
    bytes calldata data
) external only(DEFAULT_ADMIN_ROLE) {
    _mint(account, id, amount, data);
}

/**
 * @notice See definition of `_mint` in ERC1155 contract
 * @dev This implementation only allows admins to mint tokens
 * but can be changed as per requirement
 */