pragma solidity ^0.8.0;







contract FyatLuxWorld is ERC1155, ERC1155Holder, Ownable {

    using Strings for uint256;

    string private _contractURI = '';

    // A certain collection how much is it priced for.
    mapping(uint256 => uint256) editionToPrice;

    // Is a collection open for minting.
    mapping(uint256 => bool) editionToAvailability;

    // Is edition open.
    mapping(uint256 => bool) isOpenEdition;

    // If not open, what's the max supply.
    mapping(uint256 => uint256) editionAvailableSupply;

    // Edition to Merkle Tree Root for gating.
    mapping(uint256 => bytes32) editionToRoot;

    // Is the edition gated for Whitelists or Claims.
    mapping(uint256 => bool) isEditionGated;

    // How much can someone buy of a certain edition?
    mapping(uint256 => uint256) editionToMaxAllowance;

    // How much has been minted of a specific  edition.
    mapping(uint256 => uint256) editionMinted;

    mapping(uint256 => string) editionToURI;

    // How much has been minted of a specific edition by a specific member.
    mapping(uint256 => mapping(address => uint256)) editionToTally;

    // Next available edition id.
    uint256 private availableEditionId = 1;

    constructor(string memory uri) ERC1155(uri) {}

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, ERC1155Receiver) returns (bool) {
        return ERC1155.supportsInterface(interfaceId) || ERC1155Receiver.supportsInterface(interfaceId);
    }

    function uri(uint256 id) public view virtual override returns (string memory) {
        return editionToURI[id];
    }

        // Set base URI for editions.
    function setURI(uint256 edition, string memory newURI) public onlyOwner {
        editionToURI[edition] = newURI;
    }

    function getEditionMaxAllowance(uint256 edition) public view returns(uint256) {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        return editionToMaxAllowance[edition];
    }

    function getEditionPrice(uint256 edition) public view returns (uint256) {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        return editionToPrice[edition];
    }

    function getTotalMinted(uint256 edition) public view returns (uint256) {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        return editionMinted[edition];
    }

    function getEditionSize(uint256 edition) public view returns (uint256) {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        return editionAvailableSupply[edition];
    }

    function getIsEditionGated(uint256 edition) public view returns (bool) {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        return isEditionGated[edition];
    }

    function getIsOpenEdition(uint256 edition) public view returns (bool) {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        return isOpenEdition[edition];
    }

    function getIsEditionAvailable(uint256 edition) public view returns (bool) {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        return editionToAvailability[edition];
    }

    function getLatestEdition() public view returns (uint256) {
        return (availableEditionId - 1);
    }

    function getRoot(uint256 edition) external onlyOwner view returns (bytes32) {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        return editionToRoot[edition];
    }

    // Create a new edition with unlimited supply.
    function addOpenEdition(string memory editionURI, uint256 price, bool isGated, uint256 maxAllowance) public onlyOwner {
        editionToURI[availableEditionId] = editionURI;
        editionToPrice[availableEditionId] = price;
        editionToAvailability[availableEditionId] = true;
        isOpenEdition[availableEditionId] = true;
        isEditionGated[availableEditionId] = isGated;
        editionToMaxAllowance[availableEditionId] = maxAllowance;
        availableEditionId = availableEditionId + 1;
    }

    // Create a new edition with limited supply.
    function addLimitedEdition(string memory editionURI, uint256 price, uint256 size, bool isGated, uint256 maxAllowance) public onlyOwner {
        require(size > 0, 'Edition size must be non-zero.');
        editionToURI[availableEditionId] = editionURI;
        editionToPrice[availableEditionId] = price;
        editionToAvailability[availableEditionId] = true;
        isOpenEdition[availableEditionId] = false;
        isEditionGated[availableEditionId] = isGated;
        editionAvailableSupply[availableEditionId] = size;
        editionToMaxAllowance[availableEditionId] = maxAllowance;
        availableEditionId = availableEditionId + 1;
    }

    function mintEdition(uint256 edition, uint256 quantity) public onlyOwner {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        require(isOpenEdition[edition] || (editionMinted[edition] + quantity <= editionAvailableSupply[edition]), 'Mint would exceed availability.');
        editionMinted[edition] = editionMinted[edition] + quantity;
        _mint(msg.sender, edition, quantity, "");
    }

    // Change the price for an edition.
    function updateEditionPrice(uint256 edition, uint256 price) public onlyOwner {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        editionToPrice[edition] = price;
    }

    // Change the max size of existing edition.
    function updateEditionSize(uint256 edition, uint256 newSize) public onlyOwner {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        require(!isOpenEdition[edition], 'Edition must not be open.');
        editionAvailableSupply[edition] = newSize;
    }

    // Set Merkle Root to gated edition.
    function setEditionGate(uint256 edition, bytes32 newRoot) public onlyOwner {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        editionToRoot[edition] = newRoot;
    }

    function setEditionMaxAllowance(uint256 edition, uint256 allowance) public onlyOwner {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        editionToMaxAllowance[edition] = allowance;
    }

    // Set edition to be gated.
    function setIsGated(uint256 edition, bool isGated) public onlyOwner {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        isEditionGated[edition] = isGated;
    }

    // Get editions locked in contract.
    function withdrawItems(uint256 edition, uint256 quantity) public onlyOwner {
        require(balanceOf(address(this), edition) >= quantity,'No such amount of edition available for withdrawal.');
        _safeTransferFrom(address(this), msg.sender, edition, quantity, "");
    }

    // Withdraw funds to deployer wallet.
    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        payable(msg.sender).transfer(balance);
    }

    // Send some goodies to lucky person.
    function gift(uint256 edition, address member, uint256 quantity) public onlyOwner {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        require(isOpenEdition[edition] || (editionMinted[edition] + quantity <= editionAvailableSupply[edition]), 'No such amount of edition available for withdrawal.');
        editionMinted[edition] = editionMinted[edition] + quantity;
        _mint(member, edition, quantity, "");
    }

    // Make edition available for purchase.
    function setEditionIsAvailable(uint256 edition, bool isAvailable) public onlyOwner {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        editionToAvailability[edition] = isAvailable;
    }

    // Buy a part of the Fyat Lux World.
    function purchaseOpenEdition(uint256 edition, uint256 quantity, bytes32[] calldata proof) public payable {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        require(isOpenEdition[edition], 'Edition must be open.');
        require(editionToAvailability[edition], 'Edition must be available.');
        require(editionToPrice[edition] * quantity <= msg.value, 'ETH amount is not sufficient');
        require(!isEditionGated[edition] || (MerkleProof.verify(proof, editionToRoot[edition], keccak256(abi.encodePacked(msg.sender)))), 'The Gate has stopped you.');
        require(editionToMaxAllowance[edition] == 0 || (editionToMaxAllowance[edition] > 0 && editionToTally[edition][msg.sender] + quantity <= editionToMaxAllowance[edition]), 'Asked for too many');
        editionToTally[edition][msg.sender] =  editionToTally[edition][msg.sender] + quantity;
        editionMinted[edition] = editionMinted[edition] + quantity;
        _mint(msg.sender, edition, quantity, "");
    }

    // Buy a part of the Fyat Lux World.
    function purchaseLimitedEdition(uint256 edition, uint256 quantity, bytes32[] calldata proof) public payable {
        require(edition > 0 && edition < availableEditionId, 'Edition must exist');
        require(!isOpenEdition[edition], 'Edition must be closed.');
        require(editionToAvailability[edition],"Edition must be available.");
        require(editionToPrice[edition] * quantity <= msg.value, 'ETH amount is not sufficient');
        require(((editionMinted[edition] + quantity) <= editionAvailableSupply[edition]), 'No supply available to meet the order.');
        require(!isEditionGated[edition] || (MerkleProof.verify(proof, editionToRoot[edition], keccak256(abi.encodePacked(msg.sender)))), 'The Gate has stopped you.');
        require(editionToMaxAllowance[edition] == 0 || (editionToMaxAllowance[edition] > 0 && editionToTally[edition][msg.sender] + quantity <= editionToMaxAllowance[edition]), 'Asked for too many');
        editionMinted[edition] = editionMinted[edition] + quantity;
        editionToTally[edition][msg.sender] =  editionToTally[edition][msg.sender] + quantity;
        _mint(msg.sender, edition, quantity, "");
    }

    function contractURI() public view returns (string memory) {
        return _contractURI;
    }

    function setContractURI(string calldata URI) external onlyOwner {
        _contractURI = URI;
    }

}
[{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"string","name":"editionURI","type":"string"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"bool","name":"isGated","type":"bool"},{"internalType":"uint256","name":"maxAllowance","type":"uint256"}],"name":"addLimitedEdition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"editionURI","type":"string"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"isGated","type":"bool"},{"internalType":"uint256","name":"maxAllowance","type":"uint256"}],"name":"addOpenEdition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"}],"name":"getEditionMaxAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"}],"name":"getEditionPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"}],"name":"getEditionSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"}],"name":"getIsEditionAvailable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"}],"name":"getIsEditionGated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"}],"name":"getIsOpenEdition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestEdition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"}],"name":"getRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"}],"name":"getTotalMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"address","name":"member","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"gift","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mintEdition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"purchaseLimitedEdition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"purchaseOpenEdition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"URI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"bytes32","name":"newRoot","type":"bytes32"}],"name":"setEditionGate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"bool","name":"isAvailable","type":"bool"}],"name":"setEditionIsAvailable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"uint256","name":"allowance","type":"uint256"}],"name":"setEditionMaxAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"bool","name":"isGated","type":"bool"}],"name":"setIsGated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"string","name":"newURI","type":"string"}],"name":"setURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"updateEditionPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"uint256","name":"newSize","type":"uint256"}],"name":"updateEditionSize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"edition","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"withdrawItems","outputs":[],"stateMutability":"nonpayable","type":"function"}]