contract infoTokenV3 is ERC1155, Ownable, ERC1155Receiver {

    string public name = "Information Token";
    string public symbol = "IT v3";
    uint _totalSupply;
    uint oldinfotokenv1;
    uint oldinfotokenv2;
    uint mintTimestamp;
    address Rarible;

    constructor(uint _mintTimestamp) ERC1155(uri(0)) {
        _totalSupply = 0;
        oldinfotokenv1 = 747508;
        oldinfotokenv2 = 752414;
        mintTimestamp = _mintTimestamp;
        Rarible = 0xd07dc4262BCDbf85190C01c996b4C06a461d2430;
    }

    function totalSupply() external view returns (uint256) {
        return _totalSupply;
    }

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

    //Sets minting timestamp. Can only be called by the Treasury multisig after construction.
    function setMintTimestamp(uint _timestamp) external onlyOwner {
        mintTimestamp = _timestamp;
    }

    function onERC1155Received(address operator, address from, uint256 id, uint256 value, bytes calldata data) external override returns (bytes4) {
        if(tx.origin != owner()) {
            require(block.timestamp > mintTimestamp, "You're early! Minting starts later.");
        }
        require(msg.sender == Rarible, "The token being sent must be a Rarible Info Token.");
        require(id == oldinfotokenv1 || id == oldinfotokenv2, "The token being sent must be a v1 or v2 Info Token.");
        _totalSupply += value;
        require(_totalSupply <= 100, "There can only be 100 Info Token v3s.");
        _mint(from, 0, value, "0x");
        return bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"));
    }

    function onERC1155BatchReceived(address operator, address from, uint256[] memory ids, uint256[] memory values, bytes calldata data) external override returns (bytes4) {
        if(tx.origin != owner()) {
            require(block.timestamp > mintTimestamp, "You're early! Minting starts later.");
        }        
        require(msg.sender == Rarible, "The token being sent must be a Rarible Info Token.");
        for(uint i = 0; i < ids.length; i++) {
            require(ids[i] == oldinfotokenv1 || ids[i] == oldinfotokenv2, "The tokens being sent must be a v1 or v2 Info Token.");
            _totalSupply += values[i];
            require(_totalSupply <= 100, "There can only be 100 Info Token v3s.");
            _mint(from, 0, values[i], "0x");
        }
        return bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"));
    }
    
    function uri(uint id) public pure override returns (string memory output){
        require(id == 0, "There is only one token id (0) for Info Token v3.");
        string memory image64 = Base64.encode(bytes('<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 250 250"><style>.base { fill: black; font-family: menlo; font-size: 14px; }</style><rect width="100%" height="100%" fill="white"/><text x="10" y="60" class="base">Information Token</text><text x="10" y="80" class="base">v3</text></svg>'));
        string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "Information Token", "description": "What is information worth to you?", "image": "data:image/svg+xml;base64,', image64, '"}'))));
        output = string(abi.encodePacked('data:application/json;base64,', json));
    }

    //Treasury multisig rescue function, in case the DAO decides to reuse old Info Tokens. Can potentially mint duds if supply limit is not yet reached, so be careful!
    //The original Info Tokens are otherwise unretrievable without this function if deposited into this contract.
    function treasuryRescue(uint[] memory _amounts, uint[] memory _versions) external onlyOwner {
        for(uint i = 0; i < _versions.length; i++) {
            require(_versions[i] == 1 || _versions[i] == 2, "You must use '1' for Information Token v1 and '2' for Information Token v2 in version argument.");
            if(_versions[i] == 1) {
                IERC1155(Rarible).safeTransferFrom(address(this), owner(), oldinfotokenv1, _amounts[i], "0x");
            }
            if(_versions[i] == 2) {
                IERC1155(Rarible).safeTransferFrom(address(this), owner(), oldinfotokenv2, _amounts[i], "0x");
            }
        }
    }
}
function setMintTimestamp(uint _timestamp) external onlyOwner {
    mintTimestamp = _timestamp;
}

//Sets minting timestamp. Can only be called by the Treasury multisig after construction.