contract VerdandiWrapper is ERC721Enumerable,Ownable {
   
    // BaseTokenURI
    string public _baseTokenURI = 'ipfs://QmX4JzP3S6QMwBgb4syohprjGmiAFxPymGN5YRgBpjn35q/';
    
    bool public locked;
    
    event Wrapped(address indexed owner, uint indexed _tokenID);
    event Unwrapped(address indexed owner, uint indexed _tokenID);
	
    /**
     * Create contractStorage to get old Contracts and TokenID
     */
    struct contractStorage {
        address oldcontract;
        uint tokenID;
        bool minted;
     }
     
    mapping (uint => contractStorage) public contractStorageList;
    
    constructor() payable ERC721("VERDANDI WRAPPER", "VERDANDI") {
        /*
            Mainnet contracts
        0    TEST-DAT       0xc54233968Efd2d67353B51276fec7dD1c74B7516
        1    ASP2017        0xD2680aF5D4129198B3DC4C851c99de14Fce36358
        2    ASPEN-DAT      0x886844Fd66957A02F17B1f4d076d0223Ad6110Af
        3    CANDLE-DAT     0x690efd3B1eEEefE5e8FC2C2a86faAA0f3E47e08F
        4    MIMASU-DAT     0x1DD98164020E6dF4bEa7c3d7055A5Ca34741069a
        5    FIRESPLD-DAT   0x1Ae2D3784b852Db002EdB304dbbAfCE563095bCf
        6    XSTATIC-DAT    0xBe44D801f4FABDd9e2Ac0d02bc08e14E82793ae4
        7    WATCHM-DAT     0xbddFb9e893CB4CbdFE457543B4cC40B72379c63D
        8    SOLECH-DAT     0x8B0c7E33233889D51963647F791349D24958b14a
        9    TOUCH-DAT      0x26Db8592a83bc1eCd0251e840C65bbE44bEED0Ab
        10   HERELM-DAT     0x8C841acbF7E657cB8Cd96Ef36Ae3aa471a422443
        11   VERDRE-DAT     0x2445D7232428Aa10927A6b4D8DECe5C081D0Cc28
        12   NICETO-DAT     0x260D01905CD49575536F563119fd9F9977a43262
        */

        // Creating contractStorage
        contractStorageList[0] = contractStorage({
            oldcontract: 0xc54233968Efd2d67353B51276fec7dD1c74B7516,
            tokenID: 0,
            minted: false
        });
        contractStorageList[1] = contractStorage({
            oldcontract: 0xD2680aF5D4129198B3DC4C851c99de14Fce36358,
            tokenID: 1,
            minted: false
        });
        contractStorageList[2] = contractStorage({
            oldcontract: 0x886844Fd66957A02F17B1f4d076d0223Ad6110Af,
            tokenID: 2,
            minted: false
        });
        contractStorageList[3] = contractStorage({
            oldcontract: 0x690efd3B1eEEefE5e8FC2C2a86faAA0f3E47e08F,
            tokenID: 3,
            minted: false
        });
        contractStorageList[4] = contractStorage({
            oldcontract: 0x1DD98164020E6dF4bEa7c3d7055A5Ca34741069a,
            tokenID: 4,
            minted: false
        });
        contractStorageList[5] = contractStorage({
            oldcontract: 0x1Ae2D3784b852Db002EdB304dbbAfCE563095bCf,
            tokenID: 5,
            minted: false
        });
        contractStorageList[6] = contractStorage({
            oldcontract: 0xBe44D801f4FABDd9e2Ac0d02bc08e14E82793ae4,
            tokenID: 6,
            minted: false
        });
        contractStorageList[7] = contractStorage({
            oldcontract: 0xbddFb9e893CB4CbdFE457543B4cC40B72379c63D,
            tokenID: 7,
            minted: false
        });
        contractStorageList[8] = contractStorage({
            oldcontract: 0x8B0c7E33233889D51963647F791349D24958b14a,
            tokenID: 8,
            minted: false
        });
        contractStorageList[9] = contractStorage({
            oldcontract: 0x26Db8592a83bc1eCd0251e840C65bbE44bEED0Ab,
            tokenID: 9,
            minted: false
        });
        contractStorageList[10] = contractStorage({
            oldcontract: 0x8C841acbF7E657cB8Cd96Ef36Ae3aa471a422443,
            tokenID: 10,
            minted: false
        });
        contractStorageList[11] = contractStorage({
            oldcontract: 0x2445D7232428Aa10927A6b4D8DECe5C081D0Cc28,
            tokenID: 11,
            minted: false
        });
        contractStorageList[12] = contractStorage({
            oldcontract: 0x260D01905CD49575536F563119fd9F9977a43262,
            tokenID: 12,
            minted: false
        });
    }

    /**
     * Lock modifier for locking contract to make it unchangable
     */
    modifier notLocked {
        require(!locked, "Contract metadata methods are locked");
        _;
    }
    
    // Owner function to lock Metadata forever
    function lockMetadata() external onlyOwner {
        locked = false;
    }

    /**
     * Transfer and mint
     * Transfer old Token to new Contract and mint new ERC721
     * using old contract "transferFrom" function, which is callable only by owner
     */
    
    function transferAndMint(uint tokenContractID, address from) external onlyOwner {
        contractStorage storage contractStore = contractStorageList[tokenContractID];
        require(contractStore.minted == false, "NFT721: Already minted");
        
        // get Contract for Transfer
        VerdandiContracts oldContract = VerdandiContracts(contractStore.oldcontract);
        // only allow from address to be set.
        // Transfer should go to this contract
        // TransferFrom is only callable by owner (this contract has to be the owner)
        // Value = 1, all contracts only have 1 Token, and are unmintable (on old contract)
        oldContract.transferFrom(from,address(this),1);
        
        // set Minted
        require(contractStorageList[tokenContractID].minted = true,"NFT721: Error while updating storage");
        
        // Mint and Transfer to sender
        _safeMint(_msgSender(), contractStore.tokenID);
    }
	
     /**
     * Wrap - Case: When Token-Owner unwrapped and wants to rewrap
     * Transfer old Token to new Contract and mint new ERC721
     * using old contract "transferFrom" function, which is callable only by owner
     */
    
    function wrap(uint tokenContractID) external {
        contractStorage storage contractStore = contractStorageList[tokenContractID];
        require(contractStore.minted == false, "NFT721: Already minted");
        
        // get Contract for Transfer
        VerdandiContracts oldContract = VerdandiContracts(contractStore.oldcontract);
        // only allow from address to be set.
        // Transfer should go to this contract
        // TransferFrom is only callable by owner (this contract has to be the owner)
        // Value = 1, all contracts only have 1 Token, and are unmintable (on old contract)
		// Check if the message sender is the current owner of the old Token
		require(oldContract.balanceOf(_msgSender()) == 1,"NFT721: You are not the owner of the old token");
        oldContract.transferFrom(_msgSender(),address(this),1);
        
        // set Minted
        require(contractStorageList[tokenContractID].minted = true,"NFT721: Error while updating storage");
        
        // Mint and Transfer to sender
        _safeMint(_msgSender(), contractStore.tokenID);
        emit Wrapped(_msgSender(), contractStore.tokenID);
    }
	
     /**
     * UnWrap - Use-Case: When Token-Owner wants the original token
     * Transfer old Token to new Contract and mint new ERC721
     * using old contract "transferFrom" function, which is callable only by owner
     */
	    
    function unwrap(uint tokenContractID) external {     
       
        contractStorage storage contractStore = contractStorageList[tokenContractID];
        require(contractStore.minted == true, "NFT721: Already unwrapped");
        require(_exists(contractStore.tokenID), "NFT721: operator query for nonexistent token");
        
        // Check if Owner
        address owner = ERC721.ownerOf(contractStore.tokenID);
        require(owner == _msgSender(), "NFT721: You are not the owner");
		
        // get Contract for Transfer
        VerdandiContracts oldContract = VerdandiContracts(contractStore.oldcontract);
        // only allow from address to be set.
        // Transfer should go to msgSender
        // TransferFrom is only callable by owner (this contract has to be the owner)
        // Value = 1, all contracts only have 1 Token, and are unmintable (on old contract)
        oldContract.transferFrom(address(this),_msgSender(),1);
                
        // Mint and Transfer to sender
        // burn ERC721
        _burn(contractStore.tokenID);
        require(!_exists(contractStore.tokenID), "NFT721: Token has not been burned");
		
        // set UnMinted
        contractStorageList[tokenContractID].minted = false;
        require(contractStorageList[tokenContractID].minted == false,"NFT721: Error while updating storage");
       
        emit Unwrapped(_msgSender(), contractStore.tokenID);
    }
	
    /**
     * @dev set metadata only when it's not locked
     */  

    function setBaseTokenURI(string memory __baseTokenURI) public onlyOwner notLocked {
        _baseTokenURI = __baseTokenURI;
    }
    
    /**
     * @dev Returns a URI for a given token ID's metadata
     */
    function tokenURI(uint256 _tokenId) public view override returns (string memory) {
        return string(abi.encodePacked(_baseTokenURI, Strings.toString(_tokenId)));
    }
}
// VerdandiWrapper
function wrap(uint tokenContractID) external {
    contractStorage storage contractStore = contractStorageList[tokenContractID];
    require(contractStore.minted == false, "NFT721: Already minted");
        
    // get Contract for Transfer
    VerdandiContracts oldContract = VerdandiContracts(contractStore.oldcontract);
    // only allow from address to be set.
    // Transfer should go to this contract
    // TransferFrom is only callable by owner (this contract has to be the owner)
    // Value = 1, all contracts only have 1 Token, and are unmintable (on old contract)
 Check if the message sender is the current owner of the old Token
quire(oldContract.balanceOf(_msgSender()) == 1,"NFT721: You are not the owner of the old token");
    oldContract.transferFrom(_msgSender(),address(this),1);
        
    // set Minted
    require(contractStorageList[tokenContractID].minted = true,"NFT721: Error while updating storage");
        
    // Mint and Transfer to sender
    _safeMint(_msgSender(), contractStore.tokenID);
    emit Wrapped(_msgSender(), contractStore.tokenID);
}

/**
 * Wrap - Case: When Token-Owner unwrapped and wants to rewrap
 * Transfer old Token to new Contract and mint new ERC721
 * using old contract "transferFrom" function, which is callable only by owner
 */