/**

 *Submitted for verification at Etherscan.io on 2022-01-17

*/



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library SafeMath {

    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {

        unchecked {

            uint256 c = a + b;

            if (c < a) return (false, 0);

            return (true, c);

        }

    }

    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {

        unchecked {

            if (b > a) return (false, 0);

            return (true, a - b);

        }

    }

    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {

        unchecked {

            if (a == 0) return (true, 0);

            uint256 c = a * b;

            if (c / a != b) return (false, 0);

            return (true, c);

        }

    }

    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {

        unchecked {

            if (b == 0) return (false, 0);

            return (true, a / b);

        }

    }

    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {

        unchecked {

            if (b == 0) return (false, 0);

            return (true, a % b);

        }

    }

    function add(uint256 a, uint256 b) internal pure returns (uint256) {

        return a + b;

    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {

        return a - b;

    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {

        return a * b;

    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {

        return a / b;

    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {

        return a % b;

    }

    function sub(

        uint256 a,

        uint256 b,

        string memory errorMessage

    ) internal pure returns (uint256) {

        unchecked {

            require(b <= a, errorMessage);

            return a - b;

        }

    }

    function div(

        uint256 a,

        uint256 b,

        string memory errorMessage

    ) internal pure returns (uint256) {

        unchecked {

            require(b > 0, errorMessage);

            return a / b;

        }

    }

    function mod(

        uint256 a,

        uint256 b,

        string memory errorMessage

    ) internal pure returns (uint256) {

        unchecked {

            require(b > 0, errorMessage);

            return a % b;

        }

    }

}

library Strings {

    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    function toString(uint256 value) internal pure returns (string memory) {



        if (value == 0) {

            return "0";

        }

        uint256 temp = value;

        uint256 digits;

        while (temp != 0) {

            digits++;

            temp /= 10;

        }

        bytes memory buffer = new bytes(digits);

        while (value != 0) {

            digits -= 1;

            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));

            value /= 10;

        }

        return string(buffer);

    }

    function toHexString(uint256 value) internal pure returns (string memory) {

        if (value == 0) {

            return "0x00";

        }

        uint256 temp = value;

        uint256 length = 0;

        while (temp != 0) {

            length++;

            temp >>= 8;

        }

        return toHexString(value, length);

    }

    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {

        bytes memory buffer = new bytes(2 * length + 2);

        buffer[0] = "0";

        buffer[1] = "x";

        for (uint256 i = 2 * length + 1; i > 1; --i) {

            buffer[i] = _HEX_SYMBOLS[value & 0xf];

            value >>= 4;

        }

        require(value == 0, "Strings: hex length insufficient");

        return string(buffer);

    }

}

library Address {

    function isContract(address account) internal view returns (bool) {



        uint256 size;

        assembly {

            size := extcodesize(account)

        }

        return size > 0;

    }

    function sendValue(address payable recipient, uint256 amount) internal {

        require(address(this).balance >= amount, "Address: insufficient balance");



        (bool success, ) = recipient.call{value: amount}("");

        require(success, "Address: unable to send value, recipient may have reverted");

    }

    function functionCall(address target, bytes memory data) internal returns (bytes memory) {

        return functionCall(target, data, "Address: low-level call failed");

    }

    function functionCall(

        address target,

        bytes memory data,

        string memory errorMessage

    ) internal returns (bytes memory) {

        return functionCallWithValue(target, data, 0, errorMessage);

    }

    function functionCallWithValue(

        address target,

        bytes memory data,

        uint256 value

    ) internal returns (bytes memory) {

        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");

    }

    function functionCallWithValue(

        address target,

        bytes memory data,

        uint256 value,

        string memory errorMessage

    ) internal returns (bytes memory) {

        require(address(this).balance >= value, "Address: insufficient balance for call");

        require(isContract(target), "Address: call to non-contract");



        (bool success, bytes memory returndata) = target.call{value: value}(data);

        return _verifyCallResult(success, returndata, errorMessage);

    }

    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {

        return functionStaticCall(target, data, "Address: low-level static call failed");

    }

    function functionStaticCall(

        address target,

        bytes memory data,

        string memory errorMessage

    ) internal view returns (bytes memory) {

        require(isContract(target), "Address: static call to non-contract");



        (bool success, bytes memory returndata) = target.staticcall(data);

        return _verifyCallResult(success, returndata, errorMessage);

    }

    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {

        return functionDelegateCall(target, data, "Address: low-level delegate call failed");

    }

    function functionDelegateCall(

        address target,

        bytes memory data,

        string memory errorMessage

    ) internal returns (bytes memory) {

        require(isContract(target), "Address: delegate call to non-contract");



        (bool success, bytes memory returndata) = target.delegatecall(data);

        return _verifyCallResult(success, returndata, errorMessage);

    }



    function _verifyCallResult(

        bool success,

        bytes memory returndata,

        string memory errorMessage

    ) private pure returns (bytes memory) {

        if (success) {

            return returndata;

        } else {

            if (returndata.length > 0) {



                assembly {

                    let returndata_size := mload(returndata)

                    revert(add(32, returndata), returndata_size)

                }

            } else {

                revert(errorMessage);

            }

        }

    }

}

interface IERC721Receiver {

    function onERC721Received(

        address operator,

        address from,

        uint256 tokenId,

        bytes calldata data

    ) external returns (bytes4);

}

interface IERC165 {

    function supportsInterface(bytes4 interfaceId) external view returns (bool);

}

abstract contract ERC165 is IERC165 {

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {

        return interfaceId == type(IERC165).interfaceId;

    }

}

interface IERC721 is IERC165 {

    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    function balanceOf(address owner) external view returns (uint256 balance);

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function safeTransferFrom(

        address from,

        address to,

        uint256 tokenId

    ) external;

    function transferFrom(

        address from,

        address to,

        uint256 tokenId

    ) external;

    function approve(address to, uint256 tokenId) external;

    function getApproved(uint256 tokenId) external view returns (address operator);

    function setApprovalForAll(address operator, bool _approved) external;

    function isApprovedForAll(address owner, address operator) external view returns (bool);

    function safeTransferFrom(

        address from,

        address to,

        uint256 tokenId,

        bytes calldata data

    ) external;

}

interface IERC721Enumerable is IERC721 {

    function totalSupply() external view returns (uint256);

    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);

    function tokenByIndex(uint256 index) external view returns (uint256);

}

interface IERC721Metadata is IERC721 {

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function tokenURI(uint256 tokenId) external view returns (string memory);

}

abstract contract Context {

    function _msgSender() internal view virtual returns (address) {

        return msg.sender;

    }



    function _msgData() internal view virtual returns (bytes calldata) {

        return msg.data;

    }

}

abstract contract Ownable is Context {

    address private _owner;



    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor () {

        address msgSender = _msgSender();

        _owner = msgSender;

        emit OwnershipTransferred(address(0), msgSender);

    }

    function owner() public view virtual returns (address) {

        return _owner;

    }

    modifier onlyOwner() {

        require(owner() == _msgSender(), "Ownable: caller is not the owner");

        _;

    }

    function transferOwnership(address newOwner) public virtual onlyOwner {

        require(newOwner != address(0), "Ownable: new owner is the zero address");

        _setOwner(newOwner);

    }



    function _setOwner(address newOwner) private {

        address oldOwner = _owner;

        _owner = newOwner;

        emit OwnershipTransferred(oldOwner, newOwner);

    }

}

contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {

    using Address for address;

    using Strings for uint256;



    string private _name;



    string private _symbol;



    mapping(uint256 => address) private _owners;



    mapping(address => uint256) private _balances;



    mapping(uint256 => address) private _tokenApprovals;



    mapping(address => mapping(address => bool)) private _operatorApprovals;





    string public _baseURI;

    constructor(string memory name_, string memory symbol_) {

        _name = name_;

        _symbol = symbol_;

    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {

        return

            interfaceId == type(IERC721).interfaceId ||

            interfaceId == type(IERC721Metadata).interfaceId ||

            super.supportsInterface(interfaceId);

    }

    function balanceOf(address owner) public view virtual override returns (uint256) {

        require(owner != address(0), "ERC721: balance query for the zero address");

        return _balances[owner];

    }

    function ownerOf(uint256 tokenId) public view virtual override returns (address) {

        address owner = _owners[tokenId];

        require(owner != address(0), "ERC721: owner query for nonexistent token");

        return owner;

    }

    function name() public view virtual override returns (string memory) {

        return _name;

    }

    function symbol() public view virtual override returns (string memory) {

        return _symbol;

    }

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {

        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");



        string memory base = baseURI();

        return bytes(base).length > 0 ? string(abi.encodePacked(base, tokenId.toString(), ".json")) : "";

    }

    function baseURI() internal view virtual returns (string memory) {

        return _baseURI;

    }

    function approve(address to, uint256 tokenId) public virtual override {

        address owner = ERC721.ownerOf(tokenId);

        require(to != owner, "ERC721: approval to current owner");



        require(

            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),

            "ERC721: approve caller is not owner nor approved for all"

        );



        _approve(to, tokenId);

    }

    function getApproved(uint256 tokenId) public view virtual override returns (address) {

        require(_exists(tokenId), "ERC721: approved query for nonexistent token");



        return _tokenApprovals[tokenId];

    }

    function setApprovalForAll(address operator, bool approved) public virtual override {

        require(operator != _msgSender(), "ERC721: approve to caller");



        _operatorApprovals[_msgSender()][operator] = approved;

        emit ApprovalForAll(_msgSender(), operator, approved);

    }

    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {

        return _operatorApprovals[owner][operator];

    }

    function transferFrom(

        address from,

        address to,

        uint256 tokenId

    ) public virtual override {

        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");



        _transfer(from, to, tokenId);

    }

    function safeTransferFrom(

        address from,

        address to,

        uint256 tokenId

    ) public virtual override {

        safeTransferFrom(from, to, tokenId, "");

    }

    function safeTransferFrom(

        address from,

        address to,

        uint256 tokenId,

        bytes memory _data

    ) public virtual override {

        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _safeTransfer(from, to, tokenId, _data);

    }

    function _safeTransfer(

        address from,

        address to,

        uint256 tokenId,

        bytes memory _data

    ) internal virtual {

        _transfer(from, to, tokenId);

        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");

    }

    function _exists(uint256 tokenId) internal view virtual returns (bool) {

        return _owners[tokenId] != address(0);

    }

    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {

        require(_exists(tokenId), "ERC721: operator query for nonexistent token");

        address owner = ERC721.ownerOf(tokenId);

        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));

    }

    function _safeMint(address to, uint256 tokenId) internal virtual {

        _safeMint(to, tokenId, "");

    }

    function _safeMint(

        address to,

        uint256 tokenId,

        bytes memory _data

    ) internal virtual {

        _mint(to, tokenId);

        require(

            _checkOnERC721Received(address(0), to, tokenId, _data),

            "ERC721: transfer to non ERC721Receiver implementer"

        );

    }

    function _mint(address to, uint256 tokenId) internal virtual {

        require(to != address(0), "ERC721: mint to the zero address");

        require(!_exists(tokenId), "ERC721: token already minted");



        _beforeTokenTransfer(address(0), to, tokenId);



        _balances[to] += 1;

        _owners[tokenId] = to;



        emit Transfer(address(0), to, tokenId);

    }

    function _burn(uint256 tokenId) internal virtual {

        address owner = ERC721.ownerOf(tokenId);



        _beforeTokenTransfer(owner, address(0), tokenId);



        _approve(address(0), tokenId);



        _balances[owner] -= 1;

        delete _owners[tokenId];



        emit Transfer(owner, address(0), tokenId);

    }

    function _transfer(

        address from,

        address to,

        uint256 tokenId

    ) internal virtual {

        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");

        require(to != address(0), "ERC721: transfer to the zero address");



        _beforeTokenTransfer(from, to, tokenId);



        _approve(address(0), tokenId);



        _balances[from] -= 1;

        _balances[to] += 1;

        _owners[tokenId] = to;



        emit Transfer(from, to, tokenId);

    }

    function _approve(address to, uint256 tokenId) internal virtual {

        _tokenApprovals[tokenId] = to;

        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);

    }

    function _checkOnERC721Received(

        address from,

        address to,

        uint256 tokenId,

        bytes memory _data

    ) private returns (bool) {

        if (to.isContract()) {

            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {

                return retval == IERC721Receiver(to).onERC721Received.selector;

            } catch (bytes memory reason) {

                if (reason.length == 0) {

                    revert("ERC721: transfer to non ERC721Receiver implementer");

                } else {

                    assembly {

                        revert(add(32, reason), mload(reason))

                    }

                }

            }

        } else {

            return true;

        }

    }

    function _beforeTokenTransfer(

        address from,

        address to,

        uint256 tokenId

    ) internal virtual {}

}

abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {

    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;



    mapping(uint256 => uint256) private _ownedTokensIndex;



    uint256[] private _allTokens;



    mapping(uint256 => uint256) private _allTokensIndex;

    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {

        return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);

    }

    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {

        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");

        return _ownedTokens[owner][index];

    }

    function totalSupply() public view virtual override returns (uint256) {

        return _allTokens.length;

    }

    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {

        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");

        return _allTokens[index];

    }

    function _beforeTokenTransfer(

        address from,

        address to,

        uint256 tokenId

    ) internal virtual override {

        super._beforeTokenTransfer(from, to, tokenId);



        if (from == address(0)) {

            _addTokenToAllTokensEnumeration(tokenId);

        } else if (from != to) {

            _removeTokenFromOwnerEnumeration(from, tokenId);

        }

        if (to == address(0)) {

            _removeTokenFromAllTokensEnumeration(tokenId);

        } else if (to != from) {

            _addTokenToOwnerEnumeration(to, tokenId);

        }

    }

    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {

        uint256 length = ERC721.balanceOf(to);

        _ownedTokens[to][length] = tokenId;

        _ownedTokensIndex[tokenId] = length;

    }

    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {

        _allTokensIndex[tokenId] = _allTokens.length;

        _allTokens.push(tokenId);

    }

    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {



        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;

        uint256 tokenIndex = _ownedTokensIndex[tokenId];



        if (tokenIndex != lastTokenIndex) {

            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];



        }



        delete _ownedTokensIndex[tokenId];

        delete _ownedTokens[from][lastTokenIndex];

    }

    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {



        uint256 lastTokenIndex = _allTokens.length - 1;

        uint256 tokenIndex = _allTokensIndex[tokenId];



        uint256 lastTokenId = _allTokens[lastTokenIndex];





        delete _allTokensIndex[tokenId];

        _allTokens.pop();

    }

}

contract TeddyBandits is ERC721Enumerable, Ownable

{

    using SafeMath for uint256;

    using Strings for uint256;



    uint public constant _TOTALSUPPLY = 4999;

    uint public reserve=50;

    uint256 public price = 0.075 ether; 

    uint256 public status = 0; // 0-pause, 1- Public Mint

    bool public reveal = false;



    // uint private tokenId=1;



    constructor(string memory baseURI) ERC721("Teddy Bandits", "TB") {

        setBaseURI(baseURI);

        for (uint i = 0; i < reserve; i++) {

            _safeMint(msg.sender, totalsupply());

        }

    }

   

    function setBaseURI(string memory baseURI) public onlyOwner {

        _baseURI = baseURI;

    }



    function setPrice(uint256 _newPrice) public onlyOwner() {

        price = _newPrice;

    }

    function setStatus(uint8 s) public onlyOwner{

        status = s;

       

    }

    

    function setReveal() public onlyOwner{

        reveal =! reveal;

    }

   

    modifier isSaleOpen{

        require(totalSupply() < _TOTALSUPPLY, "Sale end");

        _;

    }

    function getStatus() public view returns (uint256) {

        return status;



    }

    function getPrice(uint256 _quantity) public view returns (uint256) {

       

           return _quantity*price ;

    }

    

    function giveAwayNFT(address receiver, uint chosenAmount) public onlyOwner isSaleOpen{

        require(totalSupply()+chosenAmount<=_TOTALSUPPLY,"Quantity must be lesser then MaxSupply");

        require(chosenAmount > 0, "Number of tokens can not be less than or equal to 0");

        for (uint i = 0; i < chosenAmount; i++) {

            _safeMint(receiver, totalsupply());

        }

    }

 

    function mint(uint chosenAmount) public payable isSaleOpen {

        require(totalSupply()+chosenAmount<=_TOTALSUPPLY,"Quantity must be lesser then MaxSupply");

        require(chosenAmount > 0, "Number of tokens can not be less than or equal to 0");

        

        require(price.mul(chosenAmount) == msg.value, "Sent ether value is incorrect");

        require(status == 1,"The sale is not open");



        for (uint i = 0; i < chosenAmount; i++) {

            _safeMint(msg.sender, totalsupply());

        }

    }

 

    function tokensOfOwner(address _owner) public view returns (uint256[] memory)

    {

        uint256 count = balanceOf(_owner);

        uint256[] memory result = new uint256[](count);

        for (uint256 index = 0; index < count; index++) {

            result[index] = tokenOfOwnerByIndex(_owner, index);

        }

        return result;

    }



    function withdraw() public onlyOwner {

        uint balance = address(this).balance;

        payable(msg.sender).transfer(balance);

    }

    function totalsupply() private view returns (uint)

    { 

        return super.totalSupply()+1;

    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {

        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");



        string memory base = baseURI();

        if(bytes(base).length > 0){

            return reveal ? string(abi.encodePacked(base, tokenId.toString(), ".json")) : string(abi.encodePacked("https://gateway.pinata.cloud/ipfs/QmVfdxPLU9sHpx7WBb94qaiGcG122zfd4MwpFWovckMyJZ"));

        }

        else 

        return "";

    }

    function contractURI() public view returns (string memory) {

        string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "TeddyBandits", "description": "The story revolves around a faction of teddy bears with a code. A code that must not be broken or else consequences will follow to those who violate it. Bandits will punish everyone who breaks the code; which is leaving the faction, by fining them a small fee for their punishment.", "seller_fee_basis_points": 500, "fee_recipient": "0x3bd8061C826226363088b4cc38c2Fb25b69784f8"}'))));

        json = string(abi.encodePacked('data:application/json;base64,', json));

        return json;

    }

    

    

}

library Base64 {

    bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";



    /// @notice Encodes some bytes to the base64 representation

    function encode(bytes memory data) internal pure returns (string memory) {

        uint256 len = data.length;

        if (len == 0) return "";



        // multiply by 4/3 rounded up

        uint256 encodedLen = 4 * ((len + 2) / 3);



        // Add some extra buffer at the end

        bytes memory result = new bytes(encodedLen + 32);



        bytes memory table = TABLE;



        assembly {

            let tablePtr := add(table, 1)

            let resultPtr := add(result, 32)



            for {

                let i := 0

            } lt(i, len) {



            } {

                i := add(i, 3)

                let input := and(mload(add(data, i)), 0xffffff)



                let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))

                out := shl(8, out)

                out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF))

                out := shl(8, out)

                out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF))

                out := shl(8, out)

                out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF))

                out := shl(224, out)



                mstore(resultPtr, out)



                resultPtr := add(resultPtr, 4)

            }



            switch mod(len, 3)

            case 1 {

                mstore(sub(resultPtr, 2), shl(240, 0x3d3d))

            }

            case 2 {

                mstore(sub(resultPtr, 1), shl(248, 0x3d))

            }



            mstore(result, encodedLen)

        }



        return string(result);

    }

}