0x3830…09f9

All memos sent from and to 0x3830…09f9.

ui_part1_drpc.html-1N <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀</title> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet" /> <script src="https://arweave.net/S1hqI3tgUg-m_lhtrQX9IalKxMdfGqI3fox04_xMwEI"></script> </head> <script> let isUnlocked = false; window.onload = function () { const infoButtons = document.querySelectorAll(".info"); const submitButton = document.querySelector(".submit"); const submitInfoButton = document.querySelector(".submitInfo"); const viewArtworkInfoButton = document.querySelector(".viewArtworkInfo"); const modalClose = document.querySelector(".modal-close"); const modal = document.querySelector(".modal"); infoButtons.forEach((infoButton) => { infoButton.addEventListener("click", () => { const infoModal = showModal(` <div class="modal-title">Critical text by Primavera De Filippi</div> <div class="modal-subtitle">Artist and Legal Scholar (Harvard / CNRS)</div> <div class="modal-body"> <p class="text-center">In 𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀, Andrea Chiampo points at the paradoxes of our technological systems — with blockchain as a particularly revealing case, where the promise of cryptographic immortality is perpetually undone by its own impermanence and volatility. A JPEG file is hashed onto the blockchain, before it is corrupted beyond recognition—its bytes scattered like ashes across a <b>monumental print</b> and sealed within an accompanying <b>book</b> bound using <b>ancient techniques</b>.</p> <p class="text-center">This act of deliberate corruption is not an act of destruction but one of transformation. Like a digital phoenix emerging from its own cryptographic hashes, the hashed representation of the JPEG serves as a signature of existence that persists beyond physical transformation. Locked within the immutable ledger of the blockchain, the hash exists as both a challenge and a metaphor, inviting the public to reconstitute the corrupted JPEG, while acknowledging the precarious architecture of our technological tools.</p> <p class="text-center">The collector who purchases the work does not acquire ownership of the NFT, but that of the physical artwork and its paired book that contains the instruction to recover the original JPEG file in its uncorrupted format. But the retrieval is not guaranteed; it is a gamble, a mathematical puzzle that even a quantum computer would struggle to solve. It is a puzzle that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> <p class="text-center">Chiampo's piece is a manifestation of Machina Hex Machina—a machine that curses as much as it saves. As technology has become our "<b>deus ex machina</b>", our divine intervention, what happens when it falters? What remains of our digital artefacts when the gears of the machine grind to a halt?</p> <p class="text-center">The digital artwork is a puzzle waiting to be solved. It is a challenge that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> The answer lies in the act of unravelling itself, the perpetual negotiation between creation and dissolution, where human ingenuity emerges as a recursive algorithm of resistance. Yet, there is a strange beauty in decay, as decay can become a source of reconstruction—reminding us that even as our systems collapse, the human desire to rebuild will come alive, transmuting every act of destruction into a new possibility for reconstruction.</p> <p class="text-center">QUANTUM HEX MACHINA is not merely an artwork; it is a provocation, a mirror held up to the blockchain's contradictions. It is a testament to the fragility of the systems we create and the resilience of the spirit that creates them. In its corrupted bytes and cryptographic riddles, it whispers a truth: that the act of falling apart is not an end, but a beginning—a quiet, insistent call to reimagine what lies beyond the ruins.</p> </div> <div class="modal-footer text-center"> <p style="font-size:1dvmin;line-height:initial"><i>*** Smart contract by Nahiko ***</i></p> </div> `); infoModal.children[0].style.height = "85dvmin"; }); }); submitButton.addEventListener("click", async () => { if (submitButton.classList.contains("disabled")) { return; // Don't proceed if button is disabled } try { // Get the verification result with hash and dataURI const result = await isFileCorrect(); const { dataURI, submittedFileHash } = result; console.log("Submit handler received:", { dataURI, submittedFileHash }); if (!dataURI || !submittedFileHash) { console.error("Missing dataURI or submittedFileHash"); return; // Don't proceed if verification failed } // For transactions, we need a wallet signer, not just any provider let provider; if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); } catch (err) { console.error("User rejected wallet connection:", err); showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Connection Required:</b> To submit your solution, you need to connect your Ethereum wallet.</div>` ); return; } } else { showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Not Found:</b> To submit your solution, you need an Ethereum wallet like MetaMask installed.</div>` ); return; } // Get signer const signer = await provider.getSigner(); // Create contract instance with signer to allow transactions const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer); console.log("Submitting file hash:", submittedFileHash); // Let the wallet handle the transaction UI const tx = await vaultContract.unlockNFT(submittedFileHash); // Wait for transaction to be mined const receipt = await tx.wait(); if (receipt.status === 1) { // Transaction successful - show success modal const successModal = showModal(` <div class="modal-title title">CONGRATULATIONS, YOU HAVE FINALLY SOLVED THE PUZZLE!</div> <div class="modal-body"> <div class="text-center"> <p>~</p> <p>“An eternal tunnel of static — an infinite absence of signal. A loop of technological answers birthing only more questions — drifting further from the real ones ”</p> <p>~</p> <p>Thanks to your hardwork the original image has been restored.</p> <p>You can now decide how the NFT will be experienced. Follow the instructions in the physical dossier and smart contract to upload the artwork. metadata with the recovered artwork.</p> </div> </div> `); successModal.children[0].style.padding = "8dvmin 3dvmin"; successModal.classList.add("Ihatecss"); } } catch (error) { console.error("Error in transaction:", error); // Let the wallet handle error cases - don't show our own modal } }); submitInfoButton.addEventListener("click", () => { const submitInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">While anyone may interact with this interface and attempt to submit a solution, only the wallet address registered on-chain at the time of acquisition holds the exclusive right to advance to the next phase:<br> to unlock the NFT, validate the reconstruction, and update its metadata with the recovered artwork.</div>` ); submitInfoModal.children[0].style.height = "auto"; submitInfoModal.children[0].style.width = "80dvmin"; }); viewArtworkInfoButton.addEventListener("click", () => { const viewArtworkInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">The Physical Collector may or may not choose to make the artwork available for display</div>` ); viewArtworkInfoModal.children[0].style.height = "auto"; viewArtworkInfoModal.children[0].style.width = "80dvmin"; }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") { const modal = document.querySelector(".modal"); if (modal) closeModal(modal); } }); const collectorElements = document.querySelectorAll(".collector"); collectorElements.forEach((element) => { console.log(element.textContent); element.addEventListener("click", function () { window.open("https://etherscan.io/address/" + element.textContent, "_blank"); }); }); const timer = document.querySelector(".timer"); const targetDate = new Date("April 3, 2025 13:00:00 EDT"); const timerInterval = setInterval(() => { const now = new Date(); const timeZoneDiff = now.getTimezoneOffset() * 60000; const nowUTC = new Date(now.getTime() + timeZoneDiff); const nyTimeOffset = -4 * 60 * 60000; const nowNY = new Date(nowUTC.getTime() + nyTimeOffset); const difference = targetDate - nowNY; const years = Math.floor(Math.abs(difference) / (1000 * 60 * 60 * 24 * 365.25)); const days = Math.abs( Math.floor((difference % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24)) ); const hours = Math.abs(Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))); const minutes = Math.abs(Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60))); const seconds = Math.abs(Math.floor((difference % (1000 * 60)) / 1000)); if (difference <= 0) { timer.textContent = "ENTER"; timer.classList.add("button"); timer.addEventListener("click", enterGame); const chronometer = document.querySelector(".chronometer"); chronometer.textContent = `${padZero(years)}y:${padZero(days)}:${padZero( hours )}:${padZero(minutes)}:${padZero(seconds)}`; return; } timer.textContent = `${padZero(days)}:${padZero(hours)}:${padZero(minutes)}:${padZero( seconds )}`; }, 500); setTimeout(function () { timer.style.opacity = 1; }, 500); }; function padZero(num) { return num.toString().padStart(2, "0"); } // Simplified enterGame function let isGameEntered = false; async function enterGame() { if (isGameEntered) return; try { const provider = await getProvider(); proceedToEnterGame(provider); } catch (error) { console.error("Failed to initialize provider:", error); } } // Helper function to actually enter the game once we have a provider async function proceedToEnterGame(provider) { // Call getContractData when needed await getContractData(); document.querySelector(".background").style.opacity = 1; isGameEntered = true; const cover = document.querySelector(".cover"); const game = document.querySelector(".game"); const ending = document.querySelector(".ending"); // Target element based on the unlocked status const targetElement = isUnlocked ? ending : game; cover.style.opacity = "0"; setTimeout(() => { cover.style.display = "none"; targetElement.style.display = "flex"; targetElement.style.transition = "opacity 1s ease-in"; setTimeout(() => { targetElement.style.opacity = "1"; console.log(isUnlocked ? "ENDING REACHED" : "WELCOME"); }, 50); }, 1000); } function showModal(content) { const existingModal = document.querySelector(".modal"); if (existingModal) { existingModal.remove(); } const modal = document.createElement("div"); modal.className = "modal"; modal.innerHTML = ` <div class="modal-content"> <span class="close">&times;</span> ${content} </div> `; document.body.appendChild(modal); modal.offsetHeight; modal.style.display = "flex"; setTimeout(() => { modal.style.opacity = "1"; }, 10); const closeBtn = modal.querySelector(".close"); closeBtn.onclick = () => closeModal(modal); window.onclick = (e) => { if (e.target === modal) closeModal(modal); }; return modal; } function closeModal(modal) { modal.style.opacity = "0"; setTimeout(() => { modal.remove(); }, 300); } async function isFileCorrect() { try { const fileInput = document.querySelector("textarea"); let inputText = fileInput.value.trim(); const verificationString = document.querySelector(".verificationString"); if (!inputText) { verificationString.innerHTML = ""; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } if (inputText.startsWith("0x")) { inputText = inputText.substring(2); } if (!/^[0-9a-fA-F]*$/.test(inputText)) { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } let inputBytes; try { if (inputText.length % 2 !== 0) { inputText = "0" + inputText; } inputBytes = ethers.getBytes("0x" + inputText); } catch (e) { console.error("Error parsing hex input:", e); verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } const base64Content = ethers.encodeBase64(inputBytes); const dataURI = `data:image/jpeg;base64,${base64Content}`; const dataURIBytes = ethers.toUtf8Bytes(dataURI); const submittedFileHash = ethers.keccak256(dataURIBytes); // Store first hash as submittedFileHash const packedFirstHash = ethers.solidityPacked(["bytes32"], [submittedFileHash]); const hashedFileHash = ethers.keccak256(packedFirstHash); console.log("First hash (submittedFileHash):", submittedFileHash); console.log("Final hash (hashedFileHash):", hashedFileHash); const expectedHashedFileHash = "0xb43501f79c29086d44cc94ea56ab6c0901cbc79e113f498a64dbfde145f1fa49"; if (hashedFileHash.toLowerCase() === expectedHashedFileHash.toLowerCase()) { verificationString.innerHTML = "✓ &nbsp;Quantum state observed. Reality collapses into certainty."; document.querySelector(".submit").classList.remove("disabled"); return { dataURI, submittedFileHash }; // Return an object with the values } else { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; document.querySelector(".submit").classList.add("disabled"); return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } catch (error) { console.error("Error in isFileCorrect function:", error); document.querySelector(".verificationString").innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } function stringToHexBytes(str) { return Array.from(new TextEncoder().encode(str)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } document.addEventListener("DOMContentLoaded", function () { const fileInput = document.querySelector("textarea"); const textareaContainer = document.querySelector(".textareaContainer"); let debounceTimer; fileInput.addEventListener("input", function () { clearTimeout(debounceTimer); debounceTimer = setTimeout(function () { isFileCorrect(); }, 300); }); fileInput.addEventListener("paste", function () { setTimeout(isFileCorrect, 50); }); ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ["dragenter", "dragover"].forEach((eventName) => { textareaContainer.addEventListener(eventName, highlight, false); }); ["dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, unhighlight, false); }); function highlight() { textareaContainer.style.backgroundColor = "#e6e3dc"; } function unhighlight() { textareaContainer.style.backgroundColor = "#f7f6f3"; } textareaContainer.addEventListener("drop", handleDrop, false); function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; if (files.length > 0) { const file = files[0]; readFileAsHex(file); } } function readFileAsHex(file) { const reader = new FileReader(); reader.onload = function (e) { const arrayBuffer = e.target.result; const bytes = new Uint8Array(arrayBuffer); let hexString = ""; for (let i = 0; i < bytes.length; i++) { const hex = bytes[i].toString(16).padStart(2, "0"); hexString += hex; } fileInput.value = hexString; isFileCorrect(); }; reader.readAsArrayBuffer(file); } }); // Add contract details const VAULT_ADDRESS = "0x24e9C8Aa584F7F0338ec617E3F2261F4BdC49708"; const VAULT_ABI = [ "function physicalCollectorAddress() view returns (address)", "function isUnlocked() view returns (bool)", "function unlockAddress() view returns (address)", "function unlockTimestamp() view returns (uint256)", "function owner() view returns (address)", "function fileAddress() view returns (address)", "function isFileCorrect(address potentialFileAddress) view returns (bool, string)", "function unlockNFT(bytes32 submittedFileHash) external", ]; async function getProvider() { let provider; try { provider = new ethers.JsonRpcProvider("https://eth.drpc.org"); await provider.getBlockNumber(); // Test the connection console.log("Connected to public RPC provider"); retu
N <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀</title> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet" /> <script src="https://arweave.net/S1hqI3tgUg-m_lhtrQX9IalKxMdfGqI3fox04_xMwEI"></script> </head> <script> let isUnlocked = false; window.onload = function () { const infoButtons = document.querySelectorAll(".info"); const submitButton = document.querySelector(".submit"); const submitInfoButton = document.querySelector(".submitInfo"); const viewArtworkInfoButton = document.querySelector(".viewArtworkInfo"); const modalClose = document.querySelector(".modal-close"); const modal = document.querySelector(".modal"); infoButtons.forEach((infoButton) => { infoButton.addEventListener("click", () => { const infoModal = showModal(` <div class="modal-title">Critical text by Primavera De Filippi</div> <div class="modal-subtitle">Artist and Legal Scholar (Harvard / CNRS)</div> <div class="modal-body"> <p class="text-center">In 𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀, Andrea Chiampo points at the paradoxes of our technological systems — with blockchain as a particularly revealing case, where the promise of cryptographic immortality is perpetually undone by its own impermanence and volatility. A JPEG file is hashed onto the blockchain, before it is corrupted beyond recognition—its bytes scattered like ashes across a <b>monumental print</b> and sealed within an accompanying <b>book</b> bound using <b>ancient techniques</b>.</p> <p class="text-center">This act of deliberate corruption is not an act of destruction but one of transformation. Like a digital phoenix emerging from its own cryptographic hashes, the hashed representation of the JPEG serves as a signature of existence that persists beyond physical transformation. Locked within the immutable ledger of the blockchain, the hash exists as both a challenge and a metaphor, inviting the public to reconstitute the corrupted JPEG, while acknowledging the precarious architecture of our technological tools.</p> <p class="text-center">The collector who purchases the work does not acquire ownership of the NFT, but that of the physical artwork and its paired book that contains the instruction to recover the original JPEG file in its uncorrupted format. But the retrieval is not guaranteed; it is a gamble, a mathematical puzzle that even a quantum computer would struggle to solve. It is a puzzle that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> <p class="text-center">Chiampo's piece is a manifestation of Machina Hex Machina—a machine that curses as much as it saves. As technology has become our "<b>deus ex machina</b>", our divine intervention, what happens when it falters? What remains of our digital artefacts when the gears of the machine grind to a halt?</p> <p class="text-center">The digital artwork is a puzzle waiting to be solved. It is a challenge that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> The answer lies in the act of unravelling itself, the perpetual negotiation between creation and dissolution, where human ingenuity emerges as a recursive algorithm of resistance. Yet, there is a strange beauty in decay, as decay can become a source of reconstruction—reminding us that even as our systems collapse, the human desire to rebuild will come alive, transmuting every act of destruction into a new possibility for reconstruction.</p> <p class="text-center">QUANTUM HEX MACHINA is not merely an artwork; it is a provocation, a mirror held up to the blockchain's contradictions. It is a testament to the fragility of the systems we create and the resilience of the spirit that creates them. In its corrupted bytes and cryptographic riddles, it whispers a truth: that the act of falling apart is not an end, but a beginning—a quiet, insistent call to reimagine what lies beyond the ruins.</p> </div> <div class="modal-footer text-center"> <p style="font-size:1dvmin;line-height:initial"><i>*** Smart contract by Nahiko ***</i></p> </div> `); infoModal.children[0].style.height = "85dvmin"; }); }); submitButton.addEventListener("click", async () => { if (submitButton.classList.contains("disabled")) { return; // Don't proceed if button is disabled } try { // Get the verification result with hash and dataURI const result = await isFileCorrect(); const { dataURI, submittedFileHash } = result; console.log("Submit handler received:", { dataURI, submittedFileHash }); if (!dataURI || !submittedFileHash) { console.error("Missing dataURI or submittedFileHash"); return; // Don't proceed if verification failed } // For transactions, we need a wallet signer, not just any provider let provider; if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); } catch (err) { console.error("User rejected wallet connection:", err); showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Connection Required:</b> To submit your solution, you need to connect your Ethereum wallet.</div>` ); return; } } else { showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Not Found:</b> To submit your solution, you need an Ethereum wallet like MetaMask installed.</div>` ); return; } // Get signer const signer = await provider.getSigner(); // Create contract instance with signer to allow transactions const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer); console.log("Submitting file hash:", submittedFileHash); // Let the wallet handle the transaction UI const tx = await vaultContract.unlockNFT(submittedFileHash); // Wait for transaction to be mined const receipt = await tx.wait(); if (receipt.status === 1) { // Transaction successful - show success modal const successModal = showModal(` <div class="modal-title title">CONGRATULATIONS, YOU HAVE FINALLY SOLVED THE PUZZLE!</div> <div class="modal-body"> <div class="text-center"> <p>~</p> <p>“An eternal tunnel of static — an infinite absence of signal. A loop of technological answers birthing only more questions — drifting further from the real ones ”</p> <p>~</p> <p>Thanks to your hardwork the original image has been restored.</p> <p>You can now decide how the NFT will be experienced. Follow the instructions in the physical dossier and smart contract to upload the artwork. metadata with the recovered artwork.</p> </div> </div> `); successModal.children[0].style.padding = "8dvmin 3dvmin"; successModal.classList.add("Ihatecss"); } } catch (error) { console.error("Error in transaction:", error); // Let the wallet handle error cases - don't show our own modal } }); submitInfoButton.addEventListener("click", () => { const submitInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">While anyone may interact with this interface and attempt to submit a solution, only the wallet address registered on-chain at the time of acquisition holds the exclusive right to advance to the next phase:<br> to unlock the NFT, validate the reconstruction, and update its metadata with the recovered artwork.</div>` ); submitInfoModal.children[0].style.height = "auto"; submitInfoModal.children[0].style.width = "80dvmin"; }); viewArtworkInfoButton.addEventListener("click", () => { const viewArtworkInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">The Physical Collector may or may not choose to make the artwork available for display</div>` ); viewArtworkInfoModal.children[0].style.height = "auto"; viewArtworkInfoModal.children[0].style.width = "80dvmin"; }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") { const modal = document.querySelector(".modal"); if (modal) closeModal(modal); } }); const collectorElements = document.querySelectorAll(".collector"); collectorElements.forEach((element) => { console.log(element.textContent); element.addEventListener("click", function () { window.open("https://etherscan.io/address/" + element.textContent, "_blank"); }); }); const timer = document.querySelector(".timer"); const targetDate = new Date("April 3, 2025 13:00:00 EDT"); const timerInterval = setInterval(() => { const now = new Date(); const timeZoneDiff = now.getTimezoneOffset() * 60000; const nowUTC = new Date(now.getTime() + timeZoneDiff); const nyTimeOffset = -4 * 60 * 60000; const nowNY = new Date(nowUTC.getTime() + nyTimeOffset); const difference = targetDate - nowNY; const years = Math.floor(Math.abs(difference) / (1000 * 60 * 60 * 24 * 365.25)); const days = Math.abs( Math.floor((difference % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24)) ); const hours = Math.abs(Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))); const minutes = Math.abs(Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60))); const seconds = Math.abs(Math.floor((difference % (1000 * 60)) / 1000)); if (difference <= 0) { timer.textContent = "ENTER"; timer.classList.add("button"); timer.addEventListener("click", enterGame); const chronometer = document.querySelector(".chronometer"); chronometer.textContent = `${padZero(years)}y:${padZero(days)}:${padZero( hours )}:${padZero(minutes)}:${padZero(seconds)}`; return; } timer.textContent = `${padZero(days)}:${padZero(hours)}:${padZero(minutes)}:${padZero( seconds )}`; }, 500); setTimeout(function () { timer.style.opacity = 1; }, 500); }; function padZero(num) { return num.toString().padStart(2, "0"); } // Simplified enterGame function let isGameEntered = false; async function enterGame() { if (isGameEntered) return; try { const provider = await getProvider(); proceedToEnterGame(provider); } catch (error) { console.error("Failed to initialize provider:", error); } } // Helper function to actually enter the game once we have a provider async function proceedToEnterGame(provider) { // Call getContractData when needed await getContractData(); document.querySelector(".background").style.opacity = 1; isGameEntered = true; const cover = document.querySelector(".cover"); const game = document.querySelector(".game"); const ending = document.querySelector(".ending"); // Target element based on the unlocked status const targetElement = isUnlocked ? ending : game; cover.style.opacity = "0"; setTimeout(() => { cover.style.display = "none"; targetElement.style.display = "flex"; targetElement.style.transition = "opacity 1s ease-in"; setTimeout(() => { targetElement.style.opacity = "1"; console.log(isUnlocked ? "ENDING REACHED" : "WELCOME"); }, 50); }, 1000); } function showModal(content) { const existingModal = document.querySelector(".modal"); if (existingModal) { existingModal.remove(); } const modal = document.createElement("div"); modal.className = "modal"; modal.innerHTML = ` <div class="modal-content"> <span class="close">&times;</span> ${content} </div> `; document.body.appendChild(modal); modal.offsetHeight; modal.style.display = "flex"; setTimeout(() => { modal.style.opacity = "1"; }, 10); const closeBtn = modal.querySelector(".close"); closeBtn.onclick = () => closeModal(modal); window.onclick = (e) => { if (e.target === modal) closeModal(modal); }; return modal; } function closeModal(modal) { modal.style.opacity = "0"; setTimeout(() => { modal.remove(); }, 300); } async function isFileCorrect() { try { const fileInput = document.querySelector("textarea"); let inputText = fileInput.value.trim(); const verificationString = document.querySelector(".verificationString"); if (!inputText) { verificationString.innerHTML = ""; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } if (inputText.startsWith("0x")) { inputText = inputText.substring(2); } if (!/^[0-9a-fA-F]*$/.test(inputText)) { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } let inputBytes; try { if (inputText.length % 2 !== 0) { inputText = "0" + inputText; } inputBytes = ethers.getBytes("0x" + inputText); } catch (e) { console.error("Error parsing hex input:", e); verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } const base64Content = ethers.encodeBase64(inputBytes); const dataURI = `data:image/jpeg;base64,${base64Content}`; const dataURIBytes = ethers.toUtf8Bytes(dataURI); const submittedFileHash = ethers.keccak256(dataURIBytes); // Store first hash as submittedFileHash const packedFirstHash = ethers.solidityPacked(["bytes32"], [submittedFileHash]); const hashedFileHash = ethers.keccak256(packedFirstHash); console.log("First hash (submittedFileHash):", submittedFileHash); console.log("Final hash (hashedFileHash):", hashedFileHash); const expectedHashedFileHash = "0xb43501f79c29086d44cc94ea56ab6c0901cbc79e113f498a64dbfde145f1fa49"; if (hashedFileHash.toLowerCase() === expectedHashedFileHash.toLowerCase()) { verificationString.innerHTML = "✓ &nbsp;Quantum state observed. Reality collapses into certainty."; document.querySelector(".submit").classList.remove("disabled"); return { dataURI, submittedFileHash }; // Return an object with the values } else { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; document.querySelector(".submit").classList.add("disabled"); return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } catch (error) { console.error("Error in isFileCorrect function:", error); document.querySelector(".verificationString").innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } function stringToHexBytes(str) { return Array.from(new TextEncoder().encode(str)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } document.addEventListener("DOMContentLoaded", function () { const fileInput = document.querySelector("textarea"); const textareaContainer = document.querySelector(".textareaContainer"); let debounceTimer; fileInput.addEventListener("input", function () { clearTimeout(debounceTimer); debounceTimer = setTimeout(function () { isFileCorrect(); }, 300); }); fileInput.addEventListener("paste", function () { setTimeout(isFileCorrect, 50); }); ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ["dragenter", "dragover"].forEach((eventName) => { textareaContainer.addEventListener(eventName, highlight, false); }); ["dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, unhighlight, false); }); function highlight() { textareaContainer.style.backgroundColor = "#e6e3dc"; } function unhighlight() { textareaContainer.style.backgroundColor = "#f7f6f3"; } textareaContainer.addEventListener("drop", handleDrop, false); function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; if (files.length > 0) { const file = files[0]; readFileAsHex(file); } } function readFileAsHex(file) { const reader = new FileReader(); reader.onload = function (e) { const arrayBuffer = e.target.result; const bytes = new Uint8Array(arrayBuffer); let hexString = ""; for (let i = 0; i < bytes.length; i++) { const hex = bytes[i].toString(16).padStart(2, "0"); hexString += hex; } fileInput.value = hexString; isFileCorrect(); }; reader.readAsArrayBuffer(file); } }); // Add contract details const VAULT_ADDRESS = "0x24e9C8Aa584F7F0338ec617E3F2261F4BdC49708"; const VAULT_ABI = [ "function physicalCollectorAddress() view returns (address)", "function isUnlocked() view returns (bool)", "function unlockAddress() view returns (address)", "function unlockTimestamp() view returns (uint256)", "function owner() view returns (address)", "function fileAddress() view returns (address)", "function isFileCorrect(address potentialFileAddress) view returns (bool, string)", "function unlockNFT(bytes32 submittedFileHash) external", ]; async function getProvider() { let provider; try { provider = new ethers.JsonRpcProvider("https://rpc.flashbots.net"); await provider.getBlockNumber();// Test the connection console.log("Connected to public RPC provider"); retu
N <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀</title> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet" /> <script src="https://arweave.net/S1hqI3tgUg-m_lhtrQX9IalKxMdfGqI3fox04_xMwEI"></script> </head> <script> let isUnlocked = false; window.onload = function () { const infoButtons = document.querySelectorAll(".info"); const submitButton = document.querySelector(".submit"); const submitInfoButton = document.querySelector(".submitInfo"); const viewArtworkInfoButton = document.querySelector(".viewArtworkInfo"); const modalClose = document.querySelector(".modal-close"); const modal = document.querySelector(".modal"); infoButtons.forEach((infoButton) => { infoButton.addEventListener("click", () => { const infoModal = showModal(` <div class="modal-title">Critical text by Primavera De Filippi</div> <div class="modal-subtitle">Artist and Legal Scholar (Harvard / CNRS)</div> <div class="modal-body"> <p class="text-center">In 𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀, Andrea Chiampo points at the paradoxes of our technological systems — with blockchain as a particularly revealing case, where the promise of cryptographic immortality is perpetually undone by its own impermanence and volatility. A JPEG file is hashed onto the blockchain, before it is corrupted beyond recognition—its bytes scattered like ashes across a <b>monumental print</b> and sealed within an accompanying <b>book</b> bound using <b>ancient techniques</b>.</p> <p class="text-center">This act of deliberate corruption is not an act of destruction but one of transformation. Like a digital phoenix emerging from its own cryptographic hashes, the hashed representation of the JPEG serves as a signature of existence that persists beyond physical transformation. Locked within the immutable ledger of the blockchain, the hash exists as both a challenge and a metaphor, inviting the public to reconstitute the corrupted JPEG, while acknowledging the precarious architecture of our technological tools.</p> <p class="text-center">The collector who purchases the work does not acquire ownership of the NFT, but that of the physical artwork and its paired book that contains the instruction to recover the original JPEG file in its uncorrupted format. But the retrieval is not guaranteed; it is a gamble, a mathematical puzzle that even a quantum computer would struggle to solve. It is a puzzle that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> <p class="text-center">Chiampo's piece is a manifestation of Machina Hex Machina—a machine that curses as much as it saves. As technology has become our "<b>deus ex machina</b>", our divine intervention, what happens when it falters? What remains of our digital artefacts when the gears of the machine grind to a halt?</p> <p class="text-center">The digital artwork is a puzzle waiting to be solved. It is a challenge that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> The answer lies in the act of unravelling itself, the perpetual negotiation between creation and dissolution, where human ingenuity emerges as a recursive algorithm of resistance. Yet, there is a strange beauty in decay, as decay can become a source of reconstruction—reminding us that even as our systems collapse, the human desire to rebuild will come alive, transmuting every act of destruction into a new possibility for reconstruction.</p> <p class="text-center">QUANTUM HEX MACHINA is not merely an artwork; it is a provocation, a mirror held up to the blockchain's contradictions. It is a testament to the fragility of the systems we create and the resilience of the spirit that creates them. In its corrupted bytes and cryptographic riddles, it whispers a truth: that the act of falling apart is not an end, but a beginning—a quiet, insistent call to reimagine what lies beyond the ruins.</p> </div> <div class="modal-footer text-center"> <p style="font-size:1dvmin;line-height:initial"><i>*** Smart contract by Nahiko ***</i></p> </div> `); infoModal.children[0].style.height = "85dvmin"; }); }); submitButton.addEventListener("click", async () => { if (submitButton.classList.contains("disabled")) { return; // Don't proceed if button is disabled } try { // Get the verification result with hash and dataURI const result = await isFileCorrect(); const { dataURI, submittedFileHash } = result; console.log("Submit handler received:", { dataURI, submittedFileHash }); if (!dataURI || !submittedFileHash) { console.error("Missing dataURI or submittedFileHash"); return; // Don't proceed if verification failed } // For transactions, we need a wallet signer, not just any provider let provider; if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); } catch (err) { console.error("User rejected wallet connection:", err); showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Connection Required:</b> To submit your solution, you need to connect your Ethereum wallet.</div>` ); return; } } else { showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Not Found:</b> To submit your solution, you need an Ethereum wallet like MetaMask installed.</div>` ); return; } // Get signer const signer = await provider.getSigner(); // Create contract instance with signer to allow transactions const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer); console.log("Submitting file hash:", submittedFileHash); // Let the wallet handle the transaction UI const tx = await vaultContract.unlockNFT(submittedFileHash); // Wait for transaction to be mined const receipt = await tx.wait(); if (receipt.status === 1) { // Transaction successful - show success modal const successModal = showModal(` <div class="modal-title title">CONGRATULATIONS, YOU HAVE FINALLY SOLVED THE PUZZLE!</div> <div class="modal-body"> <div class="text-center"> <p>~</p> <p>“An eternal tunnel of static — an infinite absence of signal. A loop of technological answers birthing only more questions — drifting further from the real ones ”</p> <p>~</p> <p>Thanks to your hardwork the original image has been restored.</p> <p>You can now decide how the NFT will be experienced. Follow the instructions in the physical dossier and smart contract to upload the artwork. metadata with the recovered artwork.</p> </div> </div> `); successModal.children[0].style.padding = "8dvmin 3dvmin"; successModal.classList.add("Ihatecss"); } } catch (error) { console.error("Error in transaction:", error); // Let the wallet handle error cases - don't show our own modal } }); submitInfoButton.addEventListener("click", () => { const submitInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">While anyone may interact with this interface and attempt to submit a solution, only the wallet address registered on-chain at the time of acquisition holds the exclusive right to advance to the next phase:<br> to unlock the NFT, validate the reconstruction, and update its metadata with the recovered artwork.</div>` ); submitInfoModal.children[0].style.height = "auto"; submitInfoModal.children[0].style.width = "80dvmin"; }); viewArtworkInfoButton.addEventListener("click", () => { const viewArtworkInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">The Physical Collector may or may not choose to make the artwork available for display</div>` ); viewArtworkInfoModal.children[0].style.height = "auto"; viewArtworkInfoModal.children[0].style.width = "80dvmin"; }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") { const modal = document.querySelector(".modal"); if (modal) closeModal(modal); } }); const collectorElements = document.querySelectorAll(".collector"); collectorElements.forEach((element) => { console.log(element.textContent); element.addEventListener("click", function () { window.open("https://etherscan.io/address/" + element.textContent, "_blank"); }); }); const timer = document.querySelector(".timer"); const targetDate = new Date("April 3, 2025 13:00:00 EDT"); const timerInterval = setInterval(() => { const now = new Date(); const timeZoneDiff = now.getTimezoneOffset() * 60000; const nowUTC = new Date(now.getTime() + timeZoneDiff); const nyTimeOffset = -4 * 60 * 60000; const nowNY = new Date(nowUTC.getTime() + nyTimeOffset); const difference = targetDate - nowNY; const years = Math.floor(Math.abs(difference) / (1000 * 60 * 60 * 24 * 365.25)); const days = Math.abs( Math.floor((difference % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24)) ); const hours = Math.abs(Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))); const minutes = Math.abs(Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60))); const seconds = Math.abs(Math.floor((difference % (1000 * 60)) / 1000)); if (difference <= 0) { timer.textContent = "ENTER"; timer.classList.add("button"); timer.addEventListener("click", enterGame); const chronometer = document.querySelector(".chronometer"); chronometer.textContent = `${padZero(years)}y:${padZero(days)}:${padZero( hours )}:${padZero(minutes)}:${padZero(seconds)}`; return; } timer.textContent = `${padZero(days)}:${padZero(hours)}:${padZero(minutes)}:${padZero( seconds )}`; }, 500); setTimeout(function () { timer.style.opacity = 1; }, 500); }; function padZero(num) { return num.toString().padStart(2, "0"); } // Simplified enterGame function let isGameEntered = false; async function enterGame() { if (isGameEntered) return; try { const provider = await getProvider(); proceedToEnterGame(provider); } catch (error) { console.error("Failed to initialize provider:", error); } } // Helper function to actually enter the game once we have a provider async function proceedToEnterGame(provider) { // Call getContractData when needed await getContractData(); document.querySelector(".background").style.opacity = 1; isGameEntered = true; const cover = document.querySelector(".cover"); const game = document.querySelector(".game"); const ending = document.querySelector(".ending"); // Target element based on the unlocked status const targetElement = isUnlocked ? ending : game; cover.style.opacity = "0"; setTimeout(() => { cover.style.display = "none"; targetElement.style.display = "flex"; targetElement.style.transition = "opacity 1s ease-in"; setTimeout(() => { targetElement.style.opacity = "1"; console.log(isUnlocked ? "ENDING REACHED" : "WELCOME"); }, 50); }, 1000); } function showModal(content) { const existingModal = document.querySelector(".modal"); if (existingModal) { existingModal.remove(); } const modal = document.createElement("div"); modal.className = "modal"; modal.innerHTML = ` <div class="modal-content"> <span class="close">&times;</span> ${content} </div> `; document.body.appendChild(modal); modal.offsetHeight; modal.style.display = "flex"; setTimeout(() => { modal.style.opacity = "1"; }, 10); const closeBtn = modal.querySelector(".close"); closeBtn.onclick = () => closeModal(modal); window.onclick = (e) => { if (e.target === modal) closeModal(modal); }; return modal; } function closeModal(modal) { modal.style.opacity = "0"; setTimeout(() => { modal.remove(); }, 300); } async function isFileCorrect() { try { const fileInput = document.querySelector("textarea"); let inputText = fileInput.value.trim(); const verificationString = document.querySelector(".verificationString"); if (!inputText) { verificationString.innerHTML = ""; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } if (inputText.startsWith("0x")) { inputText = inputText.substring(2); } if (!/^[0-9a-fA-F]*$/.test(inputText)) { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } let inputBytes; try { if (inputText.length % 2 !== 0) { inputText = "0" + inputText; } inputBytes = ethers.getBytes("0x" + inputText); } catch (e) { console.error("Error parsing hex input:", e); verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } const base64Content = ethers.encodeBase64(inputBytes); const dataURI = `data:image/jpeg;base64,${base64Content}`; const dataURIBytes = ethers.toUtf8Bytes(dataURI); const submittedFileHash = ethers.keccak256(dataURIBytes); // Store first hash as submittedFileHash const packedFirstHash = ethers.solidityPacked(["bytes32"], [submittedFileHash]); const hashedFileHash = ethers.keccak256(packedFirstHash); console.log("First hash (submittedFileHash):", submittedFileHash); console.log("Final hash (hashedFileHash):", hashedFileHash); const expectedHashedFileHash = "0xb43501f79c29086d44cc94ea56ab6c0901cbc79e113f498a64dbfde145f1fa49"; if (hashedFileHash.toLowerCase() === expectedHashedFileHash.toLowerCase()) { verificationString.innerHTML = "✓ &nbsp;Quantum state observed. Reality collapses into certainty."; document.querySelector(".submit").classList.remove("disabled"); return { dataURI, submittedFileHash }; // Return an object with the values } else { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; document.querySelector(".submit").classList.add("disabled"); return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } catch (error) { console.error("Error in isFileCorrect function:", error); document.querySelector(".verificationString").innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } function stringToHexBytes(str) { return Array.from(new TextEncoder().encode(str)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } document.addEventListener("DOMContentLoaded", function () { const fileInput = document.querySelector("textarea"); const textareaContainer = document.querySelector(".textareaContainer"); let debounceTimer; fileInput.addEventListener("input", function () { clearTimeout(debounceTimer); debounceTimer = setTimeout(function () { isFileCorrect(); }, 300); }); fileInput.addEventListener("paste", function () { setTimeout(isFileCorrect, 50); }); ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ["dragenter", "dragover"].forEach((eventName) => { textareaContainer.addEventListener(eventName, highlight, false); }); ["dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, unhighlight, false); }); function highlight() { textareaContainer.style.backgroundColor = "#e6e3dc"; } function unhighlight() { textareaContainer.style.backgroundColor = "#f7f6f3"; } textareaContainer.addEventListener("drop", handleDrop, false); function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; if (files.length > 0) { const file = files[0]; readFileAsHex(file); } } function readFileAsHex(file) { const reader = new FileReader(); reader.onload = function (e) { const arrayBuffer = e.target.result; const bytes = new Uint8Array(arrayBuffer); let hexString = ""; for (let i = 0; i < bytes.length; i++) { const hex = bytes[i].toString(16).padStart(2, "0"); hexString += hex; } fileInput.value = hexString; isFileCorrect(); }; reader.readAsArrayBuffer(file); } }); // Add contract details const VAULT_ADDRESS = "0x24e9C8Aa584F7F0338ec617E3F2261F4BdC49708"; const VAULT_ABI = [ "function physicalCollectorAddress() view returns (address)", "function isUnlocked() view returns (bool)", "function unlockAddress() view returns (address)", "function unlockTimestamp() view returns (uint256)", "function owner() view returns (address)", "function fileAddress() view returns (address)", "function isFileCorrect(address potentialFileAddress) view returns (bool, string)", "function unlockNFT(bytes32 submittedFileHash) external", ]; async function getProvider() { let provider; try { provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com"); await provider.getBlockNumber(); // Test the connection console.log("Connected to public RPC provider"); return provider; } catch (error) { console.warn("Public RPC failed:", error); if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); console.log("Connected using wallet"); return provider; } catch (err) { console.error("User rejected wallet connection:", err); throw new Error("Failed to connect to wallet"); } } throw new Error("No provider available"); } } // Update getContractData to use the centralized provider async function getContractData() { try { const provider = await getProvider(); const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, provider); const collectorAddress = await vaultContract.physicalCollectorAddress(); console.log("physicalCollectorAddress: " + collectorAddress); // Update first collector address element const collectorElement = document.querySelector(".collector"); if (collectorElement) { collectorElement.textContent = collectorAddress; } // Get vault unlock status isUnlocked = await vaultContract.isUnlocked(); console.log("isUnlocked: " + isUnlocked); // Variables to store file data let fileAddress = null; let jpegDataURI = null; // If the vault is unlocked, get the unlock details from state variables if (isUnlocked) { try { // Get unlock information directly from state variables const unlockAddress = await vaultContract.unlockAddress(); const unlockTimestamp = await vaultContract.unlockTimestamp(); console.log("Unlock address:", unlockAddress); console.log("Unlock timestamp:", unlockTimestamp); if (unlockTimestamp > 0) { // Check if the timestamp is valid // Convert timestamp to date const unlockDate = new Date(Number(unlockTimestamp) * 1000); console.log("Unlock date:", unlockDate.toISOString()); // Update the chronometer with the unlock timestamp const chronometer = document.querySelector(".ending .chronometer"); if (chronometer) { chronometer.textContent = `${unlockDate .getUTCDate() .toString() .padStart(2, "0")}/${(unlockDate.getUTCMonth() + 1) .toString() .padStart(2, "0")}/${unlockDate.getUTCFullYear()}`; } // Update the collector in the ending screen with unlock address const endingCollector = document.querySelector(".ending .collector"); if (endingCollector) { endingCollector.textContent = unlockAddress; } fileAddress = await vaultContract.fileAddress(); console.log("File address:", fileAddress); try { // First check if the file is correct using the Vault contract's isFileCorrect function const [isCorrect, fileContent] = await vaultContract.isFileCorrect(fileAddress); console.log("File correctness check:", isCorrect); if (isCorrect && fileContent) { jpegDataURI = fileContent; console.log("Retrieved verified JPEG data URI successfully"); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { viewArtworkButton.addEventListener("click", function () { showModal(` <div style="text-align:center;"> <div class="modal-title">QUANTUM HEX MACHINA</div> <div class="modal-subtitle">THE UNLOCKED ARTWORK</div> <div style="margin-top: 2dvmin;"> <img src="${jpegDataURI}" style="max-width: 90%; max-height: 70dvmin;" alt="Quantum Hex Machina" /> </div> </div> `); }); viewArtworkButton.classList.remove("disabled"); console.log("View Artwork button enabled"); } } else { console.log("File verification failed"); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { // Simply keep the button disabled by adding the disabled class viewArtworkButton.classList.add("disabled"); console.log("View Artwork button disabled due to file verification failure"); } } } catch (error) { console.error("Error verifying file:", error); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { // Also keep the button disabled in case of errors viewArtworkButton.classList.add("disabled"); console.log("View Artwork button disabled due to verification error"); } } } else { console.log("No unlock data found despite unlocked status"); // Set default values for testing if no timestamp const chronometer = document.querySelector(".chronometer"); if (chronometer) { chronometer.textContent = "UNLOCKED"; } } } catch (error) { console.error("Error getting unlock details:", error); } } return { collectorAddress, isUnlocked, unlockAddress: await vaultContract.unlockAddress(), unlockTimestamp: await vaultContract.unlockTimestamp(), fileAddress, jpegDataURI, }; } catch (error) { console.error("Error fetching contract data:", error); } } </script> <style> html { background-color: black; width: 100%; height: 100%; color: #6e6d69; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: "Times New Roman", serif; font-weight: 500; margin: 0; padding: 0; background-color: #ece9e2; background-image: url("https://arweave.net/0MD2DIp1YxwVD1xATJssXH54S9Xjz2lXA583PogfmpY"); background-size: cover; background-position: center; background-repeat: no-repeat; line-height: 1.2dvmin; } body { display: flex; flex-direction: column; width: 100dvmin; height: 100dvmin; align-items: center; justify-content: center; text-align: center; margin: 0; padding: 0; } .background { width: 100%; height: 100%; position: absolute; background-color: #ece9e2; opacity: 0; transition: opacity 1s; } .main { display: flex; flex-direction: column; align-items: center; gap: 1.3dvmin; transition: opacity 1s ease-in-out; margin-bottom: 0.4dvmin; z-index: 10; } .ending { margin-bottom: 6.5dvmin; display: none; opacity: 0; gap: 4dvmin; } .game { margin-bottom: 6.5dvmin; display: none; opacity: 0; gap: 4dvmin; } .title { font-size: 2.5dvmin; line-height: 2.5dvmin; letter-spacing: 0.54dvmin; text-indent: 0.54dvmin; } .subtitle { letter-spacing: 0.225dvmin; text-indent: 0.225dvmin; font-size: 1dvmin; line-height: 1dvmin; } .timer { background-color: #3e3e3e; color: #ece9e2; padding: 0.8dvmin 1.5dvmin; border-radius: 2dvmin; font-size: 1.2dvmin; transform: translateY(0.7dvmin); letter-spacing: 0.24dvmin; text-indent: 0.24dvmin; leading-trim: both; opacity: 0; transition: 1.5s opacity; } .Ihatecss { font-family: "Times New Roman", serif !important; } .button { background-color: #3e3e3e; leading-trim: both; color: #ece9e2; font-size: 1.2dvmin; padding: 0.8dvmin 1.5dvmin; border-radius: 2dvmin; cursor: pointer; transition: opacity 1.5s ease-in-out, background-color 0.1s; user-select: none; letter-spacing: 0.24dvmin; text-indent: 0.24dvmin; } .button:hover { background-color: #6e6d69; } .disabled { background-color: #aeaeae; cursor: default; } .disabled:hover { background-color: #aeaeae; } .info { padding: 0.8dvmin 2.4dvmin; margin-top: 2.2dvmin; } .titleContainer { display: flex; flex-direction: column; align-items: center; gap: 1.1dvmin; } .titleContainer > .title { font-size: 1.7dvmin; line-height: 1.7dvmin; } .titleContainer > .subtitle { font-size: 0.7dvmin; line-height: 0.7dvmin; } .inputContainer { display: flex; flex-direction: column; align-items: center; position: relative; } .textareaContainer { width: 48dvmin; display: flex; position: relative; background-color: #f7f6f3; padding: 2dvmin; padding-bottom: 9.5dvmin; align-items: center; justify-content: center; flex-direction: column; } .ending .textareaContainer { height: 48.5dvmin; } .ending .chronometerContainer { position: initial; bottom: initial; padding: 0.8dvmin 3dvmin; } .ending .collectorContainer { align-items: center; } .ending .collector { font-size: 1.2dvmin; } textarea { width: 100%; height: 48.5dvmin; background-color: #f7f6f3; font: inherit; font-size: 1.1dvmin; line-height: 1.1dvmin; color: inherit; vertical-align: top; letter-spacing: 0.18dvmin; text-align: justify; outline: none; border: none; box-shadow: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; resize: none; overflow-y: scroll; scrollbar-gutter: stable; overflow-x: auto; overflow-y: overlay; scrollbar-width: none; font-family: "Calibri", "Open Sans", sans-serif; font-family: monospace; } textarea::placeholder { color: #e0ddd7; } textarea::-webkit-scrollbar-track { background: transparent; } textarea { scrollbar-color: rgba(110, 109, 105, 0.5) transparent; } .chronometerContainer { position: absolute; bottom: 7dvmin; padding: 0.8dvmin 8dvmin; background-color: #e6e3dc; border-radius: 8dvmin; display: flex; flex-direction: column; gap: 0.2dvmin; } .verificationString { position: absolute; bottom: 13.5dvmin; font-size: 1.1dvmin; line-height: 1.1dvmin; font-family: "Calibri", "Open Sans", sans-serif; background-color: #f7f6f3; } .submitInfo { position: absolute; bottom: 3.75dvmin; right: -2.8dvmin; line-height: 1.6dvmin; width: 1.6dvmin; height: 1.6dvmin; border-radius: 50%; color: #6f6d69; border: solid 0.15dvmin #6f6d69; font-weight: 200; font-family: sans-serif; font-size: 1.5dvmin; line-height: 2dvmin; cursor: pointer; } .submitInfo:hover { opacity: 0.75; } .viewArtworkInfo { position: absolute; bottom: 0.5dvmin; right: 11dvmin; line-height: 1.6dvmin; width: 1.6dvmin; height: 1.6dvmin; border-radius: 50%; color: #6f6d69; border: solid 0.15dvmin #6f6d69; font-weight: 200; font-family: sans-serif; font-size: 1.5dvmin; line-height: 1.5dvmin; cursor: pointer; } .viewArtworkInfo:hover { opacity: 0.75; } .collectorContainer { display: flex; flex-direction: column; justify-content: flex-start; width: 100%; align-items: start; margin-top: 1dvmin; margin-left: 0.6dvmin; gap: 0.3dvmin; } .collector { font-weight: bold; text-decoration: underline; letter-spacing: 0.22dvmin; cursor: pointer; } .collector:hover { opacity: 0.6; } .collectorTitle { letter-spacing: 0.08dvmin; font-size: 0.9dvmin; line-height: 0.9dvmin; } .submit { align-self: end; border-radius: 0; } .viewArtwork { border-radius: 0; align-self: center; } .chronometer { font-size: 1.8dvmin; line-height: 1.8dvmin; } .modal { position: fixed; z-index: 100; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.3); opacity: 0; transition: opacity 0.3s ease-in-out; font-family: "Calibri", "Open Sans", sans-serif; display: flex; justify-content: center; align-items: center; font-size: 1.2dvmin; } .modal-content { background-color: #f7f6f3; padding: 3dvmin; width: 85dvmin; position: relative; border-radius: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.75dvmin; line-height: initial; } .text-center { text-align: center; } .modal-title { font-size: 1.45dvmin; line-height: 1.45dvmin; text-align: center; margin-top: 0; font-weight: 600; color: #3e3e3e; } .modal-subtitle { font-size: 1.27dvmin; line-height: 1.27dvmin; text-align: center; margin-top: 0; margin-bottom: 3dvmin; font-weight: normal; color: #3e3e3e; } .modal-body { line-height: 1.8; color: #3e3e3e; text-align: left; padding: 0 10dvmin; } .close { color: #6e6d69; position: absolute; right: 0.75dvmin; top: 0.25dvmin; font-size: 2dvmin; line-height: 2dvmin; font-weight: bold; cursor: pointer; padding: 0.5dvmin; user-select: none; } .close:hover { opacity: 0.7; } </style> <body> <div class="background"></div> <div class="main cover"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="timer">00:00:00:00</div> </div> <div class="main game"> <div class="titleContainer"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="info button">INFO</div> </div> <div class="inputContainer"> <div class="textareaContainer"> <textarea type="text" placeholder="Paste correct string here/drag in to upload a file" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" ></textarea> </div> <div class="verificationString"></div> <div class="chronometerContainer"> <div class="subtitle">UNSOLVED SINCE</div> <div class="chronometer title">00:00:00:00</div> </div> <div class="submit button disabled">SUBMIT</div> <div class="submitInfo">i</div> <div class="collectorContainer"> <div class="subtitle collectorTitle"> PHYSICAL ART COLLECTOR / WALLET ALLOWED TO CLAIM </div> <div class="subtitle collector">0x0000000000000000000000000000000000000000</div> </div> </div> </div> <div class="main ending"> <div class="titleContainer"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="info button">INFO</div> </div> <div class="inputContainer"> <div class="textareaContainer"> <div class="chronometerContainer"> <div class="subtitle">THIS ARTWORK HAS BEEN UNLOCKED</div> <div class="chronometer title">00/00/00</div> </div> <div class="collectorContainer"> <div class="subtitle collectorTitle">UNLOCKED BY</div> <div class="subtitle collector">0x0000000000000000000000000000000000000000</div> </div> </div> <div class="viewArtwork button">VIEW UNLOCKED ARTWORK</div> <div class="viewArtworkInfo">i</div> </div> </div> </body> </html>
description.txt-1*** SOLD FOR $50.0k / 28.248Ξ ON 30/04/2025 ***\n\n𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀 emerges as a new experimental artwork within Andrea Chiampo’s FUTURED PAST project — a work suspended between temporal states: created in the past, erased from our present, and awaiting resurrection in an unwritten future.\n\nA conceptual piece centered around a now-lost digital image, deliberately deleted from all digital storage — including the artist’s own devices.\n\nThe only path to recovering the work lies in reordering a scrambled hexadecimal string and submitting it through an on-chain interactive portal, custom-built to verify and reveal the hidden artwork.\n\nThe string — composed of millions of characters — was scrambled beyond the reach of today’s technologies. The artwork now rests in limbo, awaiting the arrival of quantum computing power to be resurrected and seen again.\n\nA relic of the future — like the scattered ashes of a phoenix awaiting rebirth.\n\nThe collector receives a high-quality 1/1 physical artwork and a book bound using ancient techniques, containing the full scrambled string and clear instructions for reconstruction.\n\nThey hold everything needed to solve the puzzle — except for one missing element: computing power capable of processing the near-infinite permutations required to restore the original sequence.\n\nIn an innovative model of wrapped ownership, the NFT remains sealed within its smart contract and serves as a cryptographic portal.\n\nThrough it, the collector may verify the correct sequence (against the checksum hashed on-chain), unveiling the hidden artwork and making it publicly visible through the portal. In that moment, the NFT is fully unlocked and transferred into the collector’s complete ownership.\n\nUntil then — while anyone may interact with the portal — only the collector’s registered wallet holds the power to verify, claim, or transfer eligibility.\nMore than ownership: it’s guardianship — until revelation.\n\n*** Smart contract by Nahiko ***
description.txt-1*** SOLD FOR $50.0k / 28.248Ξ ON 30/04/2025 *** 𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀 emerges as a new experimental artwork within Andrea Chiampo’s FUTURED PAST project — a work suspended between temporal states: created in the past, erased from our present, and awaiting resurrection in an unwritten future. A conceptual piece centered around a now-lost digital image, deliberately deleted from all digital storage — including the artist’s own devices. The only path to recovering the work lies in reordering a scrambled hexadecimal string and submitting it through an on-chain interactive portal, custom-built to verify and reveal the hidden artwork. The string — composed of millions of characters — was scrambled beyond the reach of today’s technologies. The artwork now rests in limbo, awaiting the arrival of quantum computing power to be resurrected and seen again. A relic of the future — like the scattered ashes of a phoenix awaiting rebirth. The collector receives a high-quality 1/1 physical artwork and a book bound using ancient techniques, containing the full scrambled string and clear instructions for reconstruction. They hold everything needed to solve the puzzle — except for one missing element: computing power capable of processing the near-infinite permutations required to restore the original sequence. In an innovative model of wrapped ownership, the NFT remains sealed within its smart contract and serves as a cryptographic portal. Through it, the collector may verify the correct sequence (against the checksum hashed on-chain), unveiling the hidden artwork and making it publicly visible through the portal. In that moment, the NFT is fully unlocked and transferred into the collector’s complete ownership. Until then — while anyone may interact with the portal — only the collector’s registered wallet holds the power to verify, claim, or transfer eligibility. More than ownership: it’s guardianship — until revelation. *** Smart contract by Nahiko ***
N <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀</title> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet" /> <script src="https://arweave.net/S1hqI3tgUg-m_lhtrQX9IalKxMdfGqI3fox04_xMwEI"></script> </head> <script> let isUnlocked = false; window.onload = function () { const infoButtons = document.querySelectorAll(".info"); const submitButton = document.querySelector(".submit"); const submitInfoButton = document.querySelector(".submitInfo"); const viewArtworkInfoButton = document.querySelector(".viewArtworkInfo"); const modalClose = document.querySelector(".modal-close"); const modal = document.querySelector(".modal"); infoButtons.forEach((infoButton) => { infoButton.addEventListener("click", () => { const infoModal = showModal(` <div class="modal-title">Critical text by Primavera De Filippi</div> <div class="modal-subtitle">Artist and Legal Scholar (Harvard / CNRS)</div> <div class="modal-body"> <p class="text-center">In 𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀, Andrea Chiampo points at the paradoxes of our technological systems — with blockchain as a particularly revealing case, where the promise of cryptographic immortality is perpetually undone by its own impermanence and volatility. A JPEG file is hashed onto the blockchain, before it is corrupted beyond recognition—its bytes scattered like ashes across a monumental print and sealed within an accompanying physical pamphlet.</p> <p class="text-center">This act of deliberate corruption is not an act of destruction but one of transformation. Like a digital phoenix emerging from its own cryptographic hashes, the hashed representation of the JPEG serves as a signature of existence that persists beyond physical transformation. Locked within the immutable ledger of the blockchain, the hash exists as both a challenge and a metaphor, inviting the public to reconstitute the corrupted JPEG, while acknowledging the precarious architecture of our technological tools.</p> <p class="text-center">The collector who purchases the work does not acquire ownership of the NFT, but that of the physical artwork and it paired pamphlet that contains the instruction to recover the original JPEG file in its uncorrupted format. But the retrieval is not guaranteed; it is a gamble, a mathematical puzzle that even a quantum computer would struggle to solve. It is a puzzle that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> <p class="text-center">Chiampo's piece is a manifestation of Machina Hex Machina—a machine that curses as much as it saves. As technology has become our "<b>deus ex machina</b>", our divine intervention, what happens when it falters? What remains of our digital artefacts when the gears of the machine grind to a halt?</p> <p class="text-center">The digital artwork is a puzzle waiting to be solved. It is a challenge that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> The answer lies in the act of unravelling itself, the perpetual negotiation between creation and dissolution, where human ingenuity emerges as a recursive algorithm of resistance. Yet, there is a strange beauty in decay, as decay can become a source of reconstruction—reminding us that even as our systems collapse, the human desire to rebuild will come alive, transmuting every act of destruction into a new possibility for reconstruction.</p> <p class="text-center">QUANTUM HEX MACHINA is not merely an artwork; it is a provocation, a mirror held up to the blockchain's contradictions. It is a testament to the fragility of the systems we create and the resilience of the spirit that creates them. In its corrupted bytes and cryptographic riddles, it whispers a truth: that the act of falling apart is not an end, but a beginning—a quiet, insistent call to reimagine what lies beyond the ruins.</p> </div> <div class="modal-footer text-center"> <p style="font-size:1dvmin;line-height:initial"><i>*** Smart contract by Nahiko ***</i></p> </div> `); infoModal.children[0].style.height = "85dvmin"; }); }); submitButton.addEventListener("click", async () => { if (submitButton.classList.contains("disabled")) { return; // Don't proceed if button is disabled } try { // Get the verification result with hash and dataURI const result = await isFileCorrect(); const { dataURI, submittedFileHash } = result; console.log("Submit handler received:", { dataURI, submittedFileHash }); if (!dataURI || !submittedFileHash) { console.error("Missing dataURI or submittedFileHash"); return; // Don't proceed if verification failed } // For transactions, we need a wallet signer, not just any provider let provider; if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); } catch (err) { console.error("User rejected wallet connection:", err); showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Connection Required:</b> To submit your solution, you need to connect your Ethereum wallet.</div>` ); return; } } else { showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Not Found:</b> To submit your solution, you need an Ethereum wallet like MetaMask installed.</div>` ); return; } // Get signer const signer = await provider.getSigner(); // Create contract instance with signer to allow transactions const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer); console.log("Submitting file hash:", submittedFileHash); // Let the wallet handle the transaction UI const tx = await vaultContract.unlockNFT(submittedFileHash); // Wait for transaction to be mined const receipt = await tx.wait(); if (receipt.status === 1) { // Transaction successful - show success modal const successModal = showModal(` <div class="modal-title title">CONGRATULATIONS, YOU HAVE FINALLY SOLVED THE PUZZLE!</div> <div class="modal-body"> <div class="text-center"> <p>~</p> <p>“An eternal tunnel of static — an infinite absence of signal. A loop of technological answers birthing only more questions — drifting further from the real ones ”</p> <p>~</p> <p>Thanks to your hardwork the original image has been restored.</p> <p>You can now decide how the NFT will be experienced. Follow the instructions in the physical dossier and smart contract to upload the artwork. metadata with the recovered artwork.</p> </div> </div> `); successModal.children[0].style.padding = "8dvmin 3dvmin"; successModal.classList.add("Ihatecss"); } } catch (error) { console.error("Error in transaction:", error); // Let the wallet handle error cases - don't show our own modal } }); submitInfoButton.addEventListener("click", () => { const submitInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">While anyone may interact with this interface and attempt to submit a solution, only the wallet address registered on-chain at the time of acquisition holds the exclusive right to advance to the next phase:<br> to unlock the NFT, validate the reconstruction, and update its metadata with the recovered artwork.</div>` ); submitInfoModal.children[0].style.height = "auto"; submitInfoModal.children[0].style.width = "80dvmin"; }); viewArtworkInfoButton.addEventListener("click", () => { const viewArtworkInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">The Physical Collector may or may not choose to make the artwork available for display</div>` ); viewArtworkInfoModal.children[0].style.height = "auto"; viewArtworkInfoModal.children[0].style.width = "80dvmin"; }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") { const modal = document.querySelector(".modal"); if (modal) closeModal(modal); } }); const collectorElements = document.querySelectorAll(".collector"); collectorElements.forEach((element) => { console.log(element.textContent); element.addEventListener("click", function () { window.open("https://etherscan.io/address/" + element.textContent, "_blank"); }); }); const timer = document.querySelector(".timer"); const targetDate = new Date("April 3, 2025 13:00:00 EDT"); const timerInterval = setInterval(() => { const now = new Date(); const timeZoneDiff = now.getTimezoneOffset() * 60000; const nowUTC = new Date(now.getTime() + timeZoneDiff); const nyTimeOffset = -4 * 60 * 60000; const nowNY = new Date(nowUTC.getTime() + nyTimeOffset); const difference = targetDate - nowNY; const years = Math.floor(Math.abs(difference) / (1000 * 60 * 60 * 24 * 365.25)); const days = Math.abs( Math.floor((difference % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24)) ); const hours = Math.abs(Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))); const minutes = Math.abs(Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60))); const seconds = Math.abs(Math.floor((difference % (1000 * 60)) / 1000)); if (difference <= 0) { timer.textContent = "ENTER"; timer.classList.add("button"); timer.addEventListener("click", enterGame); const chronometer = document.querySelector(".chronometer"); chronometer.textContent = `${padZero(years)}y:${padZero(days)}:${padZero( hours )}:${padZero(minutes)}:${padZero(seconds)}`; return; } timer.textContent = `${padZero(days)}:${padZero(hours)}:${padZero(minutes)}:${padZero( seconds )}`; }, 500); setTimeout(function () { timer.style.opacity = 1; }, 500); }; function padZero(num) { return num.toString().padStart(2, "0"); } // Simplified enterGame function let isGameEntered = false; async function enterGame() { if (isGameEntered) return; try { const provider = await getProvider(); proceedToEnterGame(provider); } catch (error) { console.error("Failed to initialize provider:", error); } } // Helper function to actually enter the game once we have a provider async function proceedToEnterGame(provider) { // Call getContractData when needed await getContractData(); document.querySelector(".background").style.opacity = 1; isGameEntered = true; const cover = document.querySelector(".cover"); const game = document.querySelector(".game"); const ending = document.querySelector(".ending"); // Target element based on the unlocked status const targetElement = isUnlocked ? ending : game; cover.style.opacity = "0"; setTimeout(() => { cover.style.display = "none"; targetElement.style.display = "flex"; targetElement.style.transition = "opacity 1s ease-in"; setTimeout(() => { targetElement.style.opacity = "1"; console.log(isUnlocked ? "ENDING REACHED" : "WELCOME"); }, 50); }, 1000); } function showModal(content) { const existingModal = document.querySelector(".modal"); if (existingModal) { existingModal.remove(); } const modal = document.createElement("div"); modal.className = "modal"; modal.innerHTML = ` <div class="modal-content"> <span class="close">&times;</span> ${content} </div> `; document.body.appendChild(modal); modal.offsetHeight; modal.style.display = "flex"; setTimeout(() => { modal.style.opacity = "1"; }, 10); const closeBtn = modal.querySelector(".close"); closeBtn.onclick = () => closeModal(modal); window.onclick = (e) => { if (e.target === modal) closeModal(modal); }; return modal; } function closeModal(modal) { modal.style.opacity = "0"; setTimeout(() => { modal.remove(); }, 300); } async function isFileCorrect() { try { const fileInput = document.querySelector("textarea"); let inputText = fileInput.value.trim(); const verificationString = document.querySelector(".verificationString"); if (!inputText) { verificationString.innerHTML = ""; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } if (inputText.startsWith("0x")) { inputText = inputText.substring(2); } if (!/^[0-9a-fA-F]*$/.test(inputText)) { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } let inputBytes; try { if (inputText.length % 2 !== 0) { inputText = "0" + inputText; } inputBytes = ethers.getBytes("0x" + inputText); } catch (e) { console.error("Error parsing hex input:", e); verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } const base64Content = ethers.encodeBase64(inputBytes); const dataURI = `data:image/jpeg;base64,${base64Content}`; const dataURIBytes = ethers.toUtf8Bytes(dataURI); const submittedFileHash = ethers.keccak256(dataURIBytes); // Store first hash as submittedFileHash const packedFirstHash = ethers.solidityPacked(["bytes32"], [submittedFileHash]); const hashedFileHash = ethers.keccak256(packedFirstHash); console.log("First hash (submittedFileHash):", submittedFileHash); console.log("Final hash (hashedFileHash):", hashedFileHash); const expectedHashedFileHash = "0xb43501f79c29086d44cc94ea56ab6c0901cbc79e113f498a64dbfde145f1fa49"; if (hashedFileHash.toLowerCase() === expectedHashedFileHash.toLowerCase()) { verificationString.innerHTML = "✓ &nbsp;Quantum state observed. Reality collapses into certainty."; document.querySelector(".submit").classList.remove("disabled"); return { dataURI, submittedFileHash }; // Return an object with the values } else { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; document.querySelector(".submit").classList.add("disabled"); return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } catch (error) { console.error("Error in isFileCorrect function:", error); document.querySelector(".verificationString").innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } function stringToHexBytes(str) { return Array.from(new TextEncoder().encode(str)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } document.addEventListener("DOMContentLoaded", function () { const fileInput = document.querySelector("textarea"); const textareaContainer = document.querySelector(".textareaContainer"); let debounceTimer; fileInput.addEventListener("input", function () { clearTimeout(debounceTimer); debounceTimer = setTimeout(function () { isFileCorrect(); }, 300); }); fileInput.addEventListener("paste", function () { setTimeout(isFileCorrect, 50); }); ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ["dragenter", "dragover"].forEach((eventName) => { textareaContainer.addEventListener(eventName, highlight, false); }); ["dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, unhighlight, false); }); function highlight() { textareaContainer.style.backgroundColor = "#e6e3dc"; } function unhighlight() { textareaContainer.style.backgroundColor = "#f7f6f3"; } textareaContainer.addEventListener("drop", handleDrop, false); function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; if (files.length > 0) { const file = files[0]; readFileAsHex(file); } } function readFileAsHex(file) { const reader = new FileReader(); reader.onload = function (e) { const arrayBuffer = e.target.result; const bytes = new Uint8Array(arrayBuffer); let hexString = ""; for (let i = 0; i < bytes.length; i++) { const hex = bytes[i].toString(16).padStart(2, "0"); hexString += hex; } fileInput.value = hexString; isFileCorrect(); }; reader.readAsArrayBuffer(file); } }); // Add contract details const VAULT_ADDRESS = "0x24e9C8Aa584F7F0338ec617E3F2261F4BdC49708"; const VAULT_ABI = [ "function physicalCollectorAddress() view returns (address)", "function isUnlocked() view returns (bool)", "function unlockAddress() view returns (address)", "function unlockTimestamp() view returns (uint256)", "function owner() view returns (address)", "function fileAddress() view returns (address)", "function isFileCorrect(address potentialFileAddress) view returns (bool, string)", "function unlockNFT(bytes32 submittedFileHash) external", ]; async function getProvider() { let provider; try { provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com"); await provider.getBlockNumber(); // Test the connection console.log("Connected to public RPC provider"); return provider; } catch (error) { console.warn("Public RPC failed:", error); if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); console.log("Connected using wallet"); return provider; } catch (err) { console.error("User rejected wallet connection:", err); throw new Error("Failed to connect to wallet"); } } throw new Error("No provider available"); } } // Update getContractData to use the centralized provider async function getContractData() { try { const provider = await getProvider(); const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, provider); const collectorAddress = await vaultContract.physicalCollectorAddress(); console.log("physicalCollectorAddress: " + collectorAddress); // Update first collector address element const collectorElement = document.querySelector(".collector"); if (collectorElement) { collectorElement.textContent = collectorAddress; } // Get vault unlock status isUnlocked = await vaultContract.isUnlocked(); console.log("isUnlocked: " + isUnlocked); // Variables to store file data let fileAddress = null; let jpegDataURI = null; // If the vault is unlocked, get the unlock details from state variables if (isUnlocked) { try { // Get unlock information directly from state variables const unlockAddress = await vaultContract.unlockAddress(); const unlockTimestamp = await vaultContract.unlockTimestamp(); console.log("Unlock address:", unlockAddress); console.log("Unlock timestamp:", unlockTimestamp); if (unlockTimestamp > 0) { // Check if the timestamp is valid // Convert timestamp to date const unlockDate = new Date(Number(unlockTimestamp) * 1000); console.log("Unlock date:", unlockDate.toISOString()); // Update the chronometer with the unlock timestamp const chronometer = document.querySelector(".ending .chronometer"); if (chronometer) { chronometer.textContent = `${unlockDate .getUTCDate() .toString() .padStart(2, "0")}/${(unlockDate.getUTCMonth() + 1) .toString() .padStart(2, "0")}/${unlockDate.getUTCFullYear()}`; } // Update the collector in the ending screen with unlock address const endingCollector = document.querySelector(".ending .collector"); if (endingCollector) { endingCollector.textContent = unlockAddress; } fileAddress = await vaultContract.fileAddress(); console.log("File address:", fileAddress); try { // First check if the file is correct using the Vault contract's isFileCorrect function const [isCorrect, fileContent] = await vaultContract.isFileCorrect(fileAddress); console.log("File correctness check:", isCorrect); if (isCorrect && fileContent) { jpegDataURI = fileContent; console.log("Retrieved verified JPEG data URI successfully"); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { viewArtworkButton.addEventListener("click", function () { showModal(` <div style="text-align:center;"> <div class="modal-title">QUANTUM HEX MACHINA</div> <div class="modal-subtitle">THE UNLOCKED ARTWORK</div> <div style="margin-top: 2dvmin;"> <img src="${jpegDataURI}" style="max-width: 90%; max-height: 70dvmin;" alt="Quantum Hex Machina" /> </div> </div> `); }); viewArtworkButton.classList.remove("disabled"); console.log("View Artwork button enabled"); } } else { console.log("File verification failed"); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { // Simply keep the button disabled by adding the disabled class viewArtworkButton.classList.add("disabled"); console.log("View Artwork button disabled due to file verification failure"); } } } catch (error) { console.error("Error verifying file:", error); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { // Also keep the button disabled in case of errors viewArtworkButton.classList.add("disabled"); console.log("View Artwork button disabled due to verification error"); } } } else { console.log("No unlock data found despite unlocked status"); // Set default values for testing if no timestamp const chronometer = document.querySelector(".chronometer"); if (chronometer) { chronometer.textContent = "UNLOCKED"; } } } catch (error) { console.error("Error getting unlock details:", error); } } return { collectorAddress, isUnlocked, unlockAddress: await vaultContract.unlockAddress(), unlockTimestamp: await vaultContract.unlockTimestamp(), fileAddress, jpegDataURI, }; } catch (error) { console.error("Error fetching contract data:", error); } } </script> <style> html { background-color: black; width: 100%; height: 100%; color: #6e6d69; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: "Times New Roman", serif; font-weight: 500; margin: 0; padding: 0; background-color: #ece9e2; background-image: url("https://arweave.net/0MD2DIp1YxwVD1xATJssXH54S9Xjz2lXA583PogfmpY"); background-size: cover; background-position: center; background-repeat: no-repeat; line-height: 1.2dvmin; } body { display: flex; flex-direction: column; width: 100dvmin; height: 100dvmin; align-items: center; justify-content: center; text-align: center; margin: 0; padding: 0; } .background { width: 100%; height: 100%; position: absolute; background-color: #ece9e2; opacity: 0; transition: opacity 1s; } .main { display: flex; flex-direction: column; align-items: center; gap: 1.3dvmin; transition: opacity 1s ease-in-out; margin-bottom: 0.4dvmin; z-index: 10; } .ending { margin-bottom: 6.5dvmin; display: none; opacity: 0; gap: 4dvmin; } .game { margin-bottom: 6.5dvmin; display: none; opacity: 0; gap: 4dvmin; } .title { font-size: 2.5dvmin; line-height: 2.5dvmin; letter-spacing: 0.54dvmin; text-indent: 0.54dvmin; } .subtitle { letter-spacing: 0.225dvmin; text-indent: 0.225dvmin; font-size: 1dvmin; line-height: 1dvmin; } .timer { background-color: #3e3e3e; color: #ece9e2; padding: 0.8dvmin 1.5dvmin; border-radius: 2dvmin; font-size: 1.2dvmin; transform: translateY(0.7dvmin); letter-spacing: 0.24dvmin; text-indent: 0.24dvmin; leading-trim: both; opacity: 0; transition: 1.5s opacity; } .Ihatecss { font-family: "Times New Roman", serif !important; } .button { background-color: #3e3e3e; leading-trim: both; color: #ece9e2; font-size: 1.2dvmin; padding: 0.8dvmin 1.5dvmin; border-radius: 2dvmin; cursor: pointer; transition: opacity 1.5s ease-in-out, background-color 0.1s; user-select: none; letter-spacing: 0.24dvmin; text-indent: 0.24dvmin; } .button:hover { background-color: #6e6d69; } .disabled { background-color: #aeaeae; cursor: default; } .disabled:hover { background-color: #aeaeae; } .info { padding: 0.8dvmin 2.4dvmin; margin-top: 2.2dvmin; } .titleContainer { display: flex; flex-direction: column; align-items: center; gap: 1.1dvmin; } .titleContainer > .title { font-size: 1.7dvmin; line-height: 1.7dvmin; } .titleContainer > .subtitle { font-size: 0.7dvmin; line-height: 0.7dvmin; } .inputContainer { display: flex; flex-direction: column; align-items: center; position: relative; } .textareaContainer { width: 48dvmin; display: flex; position: relative; background-color: #f7f6f3; padding: 2dvmin; padding-bottom: 9.5dvmin; align-items: center; justify-content: center; flex-direction: column; } .ending .textareaContainer { height: 48.5dvmin; } .ending .chronometerContainer { position: initial; bottom: initial; padding: 0.8dvmin 3dvmin; } .ending .collectorContainer { align-items: center; } .ending .collector { font-size: 1.2dvmin; } textarea { width: 100%; height: 48.5dvmin; background-color: #f7f6f3; font: inherit; font-size: 1.1dvmin; line-height: 1.1dvmin; color: inherit; vertical-align: top; letter-spacing: 0.18dvmin; text-align: justify; outline: none; border: none; box-shadow: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; resize: none; overflow-y: scroll; scrollbar-gutter: stable; overflow-x: auto; overflow-y: overlay; scrollbar-width: none; font-family: "Calibri", "Open Sans", sans-serif; font-family: monospace; } textarea::placeholder { color: #e0ddd7; } textarea::-webkit-scrollbar-track { background: transparent; } textarea { scrollbar-color: rgba(110, 109, 105, 0.5) transparent; } .chronometerContainer { position: absolute; bottom: 7dvmin; padding: 0.8dvmin 8dvmin; background-color: #e6e3dc; border-radius: 8dvmin; display: flex; flex-direction: column; gap: 0.2dvmin; } .verificationString { position: absolute; bottom: 13.5dvmin; font-size: 1.1dvmin; line-height: 1.1dvmin; font-family: "Calibri", "Open Sans", sans-serif; background-color: #f7f6f3; } .submitInfo { position: absolute; bottom: 3.75dvmin; right: -2.8dvmin; line-height: 1.6dvmin; width: 1.6dvmin; height: 1.6dvmin; border-radius: 50%; color: #6f6d69; border: solid 0.15dvmin #6f6d69; font-weight: 200; font-family: sans-serif; font-size: 1.5dvmin; line-height: 2dvmin; cursor: pointer; } .submitInfo:hover { opacity: 0.75; } .viewArtworkInfo { position: absolute; bottom: 0.5dvmin; right: 11dvmin; line-height: 1.6dvmin; width: 1.6dvmin; height: 1.6dvmin; border-radius: 50%; color: #6f6d69; border: solid 0.15dvmin #6f6d69; font-weight: 200; font-family: sans-serif; font-size: 1.5dvmin; line-height: 1.5dvmin; cursor: pointer; } .viewArtworkInfo:hover { opacity: 0.75; } .collectorContainer { display: flex; flex-direction: column; justify-content: flex-start; width: 100%; align-items: start; margin-top: 1dvmin; margin-left: 0.6dvmin; gap: 0.3dvmin; } .collector { font-weight: bold; text-decoration: underline; letter-spacing: 0.22dvmin; cursor: pointer; } .collector:hover { opacity: 0.6; } .collectorTitle { letter-spacing: 0.08dvmin; font-size: 0.9dvmin; line-height: 0.9dvmin; } .submit { align-self: end; border-radius: 0; } .viewArtwork { border-radius: 0; align-self: center; } .chronometer { font-size: 1.8dvmin; line-height: 1.8dvmin; } .modal { position: fixed; z-index: 100; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.3); opacity: 0; transition: opacity 0.3s ease-in-out; font-family: "Calibri", "Open Sans", sans-serif; display: flex; justify-content: center; align-items: center; font-size: 1.2dvmin; } .modal-content { background-color: #f7f6f3; padding: 3dvmin; width: 85dvmin; position: relative; border-radius: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.75dvmin; line-height: initial; } .text-center { text-align: center; } .modal-title { font-size: 1.45dvmin; line-height: 1.45dvmin; text-align: center; margin-top: 0; font-weight: 600; color: #3e3e3e; } .modal-subtitle { font-size: 1.27dvmin; line-height: 1.27dvmin; text-align: center; margin-top: 0; margin-bottom: 3dvmin; font-weight: normal; color: #3e3e3e; } .modal-body { line-height: 1.8; color: #3e3e3e; text-align: left; padding: 0 10dvmin; } .close { color: #6e6d69; position: absolute; right: 0.75dvmin; top: 0.25dvmin; font-size: 2dvmin; line-height: 2dvmin; font-weight: bold; cursor: pointer; padding: 0.5dvmin; user-select: none; } .close:hover { opacity: 0.7; } </style> <body> <div class="background"></div> <div class="main cover"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="timer">00:00:00:00</div> </div> <div class="main game"> <div class="titleContainer"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="info button">INFO</div> </div> <div class="inputContainer"> <div class="textareaContainer"> <textarea type="text" placeholder="Paste correct string here/drag in to upload a file" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" ></textarea> </div> <div class="verificationString"></div> <div class="chronometerContainer"> <div class="subtitle">UNSOLVED SINCE</div> <div class="chronometer title">00:00:00:00</div> </div> <div class="submit button disabled">SUBMIT</div> <div class="submitInfo">i</div> <div class="collectorContainer"> <div class="subtitle collectorTitle"> PHYSICAL ART COLLECTOR / WALLET ALLOWED TO CLAIM </div> <div class="subtitle collector">0x0000000000000000000000000000000000000000</div> </div> </div> </div> <div class="main ending"> <div class="titleContainer"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="info button">INFO</div> </div> <div class="inputContainer"> <div class="textareaContainer"> <div class="chronometerContainer"> <div class="subtitle">THIS ARTWORK HAS BEEN UNLOCKED</div> <div class="chronometer title">00/00/00</div> </div> <div class="collectorContainer"> <div class="subtitle collectorTitle">UNLOCKED BY</div> <div class="subtitle collector">0x0000000000000000000000000000000000000000</div> </div> </div> <div class="viewArtwork button">VIEW UNLOCKED ARTWORK</div> <div class="viewArtworkInfo">i</div> </div> </div> </body> </html>
N <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀</title> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet" /> <script src="https://arweave.net/S1hqI3tgUg-m_lhtrQX9IalKxMdfGqI3fox04_xMwEI"></script> </head> <script> let isUnlocked = false; window.onload = function () { const infoButtons = document.querySelectorAll(".info"); const submitButton = document.querySelector(".submit"); const submitInfoButton = document.querySelector(".submitInfo"); const viewArtworkInfoButton = document.querySelector(".viewArtworkInfo"); const modalClose = document.querySelector(".modal-close"); const modal = document.querySelector(".modal"); infoButtons.forEach((infoButton) => { infoButton.addEventListener("click", () => { const infoModal = showModal(` <div class="modal-title">Critical text by Primavera De Filippi</div> <div class="modal-subtitle">Artist and Legal Scholar (Harvard / CNRS)</div> <div class="modal-body"> <p class="text-center">In 𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀, Andrea Chiampo points at the paradoxes of our technological systems — with blockchain as a particularly revealing case, where the promise of cryptographic immortality is perpetually undone by its own impermanence and volatility. A JPEG file is hashed onto the blockchain, before it is corrupted beyond recognition—its bytes scattered like ashes across a monumental print and sealed within an accompanying physical pamphlet.</p> <p class="text-center">This act of deliberate corruption is not an act of destruction but one of transformation. Like a digital phoenix emerging from its own cryptographic hashes, the hashed representation of the JPEG serves as a signature of existence that persists beyond physical transformation. Locked within the immutable ledger of the blockchain, the hash exists as both a challenge and a metaphor, inviting the public to reconstitute the corrupted JPEG, while acknowledging the precarious architecture of our technological tools.</p> <p class="text-center">The collector who purchases the work does not acquire ownership of the NFT, but that of the physical artwork and it paired pamphlet that contains the instruction to recover the original JPEG file in its uncorrupted format. But the retrieval is not guaranteed; it is a gamble, a mathematical puzzle that even a quantum computer would struggle to solve. It is a puzzle that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> <p class="text-center">Chiampo's piece is a manifestation of Machina Hex Machina—a machine that curses as much as it saves. As technology has become our "<b>deus ex machina</b>", our divine intervention, what happens when it falters? What remains of our digital artefacts when the gears of the machine grind to a halt?</p> <p class="text-center">The digital artwork is a puzzle waiting to be solved. It is a challenge that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> The answer lies in the act of unravelling itself, the perpetual negotiation between creation and dissolution, where human ingenuity emerges as a recursive algorithm of resistance. Yet, there is a strange beauty in decay, as decay can become a source of reconstruction—reminding us that even as our systems collapse, the human desire to rebuild will come alive, transmuting every act of destruction into a new possibility for reconstruction.</p> <p class="text-center">QUANTUM HEX MACHINA is not merely an artwork; it is a provocation, a mirror held up to the blockchain's contradictions. It is a testament to the fragility of the systems we create and the resilience of the spirit that creates them. In its corrupted bytes and cryptographic riddles, it whispers a truth: that the act of falling apart is not an end, but a beginning—a quiet, insistent call to reimagine what lies beyond the ruins.</p> </div> <div class="modal-footer text-center"> <p style="font-size:1dvmin;"><i>*** Smart contract by Nahiko ***</i></p> </div> `); infoModal.children[0].style.height = "85dvmin"; }); }); submitButton.addEventListener("click", async () => { if (submitButton.classList.contains("disabled")) { return; // Don't proceed if button is disabled } try { // Get the verification result with hash and dataURI const result = await isFileCorrect(); const { dataURI, submittedFileHash } = result; console.log("Submit handler received:", { dataURI, submittedFileHash }); if (!dataURI || !submittedFileHash) { console.error("Missing dataURI or submittedFileHash"); return; // Don't proceed if verification failed } // For transactions, we need a wallet signer, not just any provider let provider; if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); } catch (err) { console.error("User rejected wallet connection:", err); showModal( `<div style="text-align:left;font-size:1.5dvmin;padding: 2dvmin 4dvmin;"><b>Wallet Connection Required:</b> To submit your solution, you need to connect your Ethereum wallet.</div>` ); return; } } else { showModal( `<div style="text-align:left;font-size:1.5dvmin;padding: 2dvmin 4dvmin;"><b>Wallet Not Found:</b> To submit your solution, you need an Ethereum wallet like MetaMask installed.</div>` ); return; } // Get signer const signer = await provider.getSigner(); // Create contract instance with signer to allow transactions const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer); console.log("Submitting file hash:", submittedFileHash); // Let the wallet handle the transaction UI const tx = await vaultContract.unlockNFT(submittedFileHash); // Wait for transaction to be mined const receipt = await tx.wait(); if (receipt.status === 1) { // Transaction successful - show success modal const successModal = showModal(` <div class="modal-title title">CONGRATULATIONS, YOU HAVE FINALLY SOLVED THE PUZZLE!</div> <div class="modal-body"> <div class="text-center"> <p>~</p> <p>“An eternal tunnel of static — an infinite absence of signal. A loop of technological answers birthing only more questions — drifting further from the real ones ”</p> <p>~</p> <p>Thanks to your hardwork the original image has been restored.</p> <p>You can now decide how the NFT will be experienced. Follow the instructions in the physical dossier and smart contract to upload the artwork. metadata with the recovered artwork.</p> </div> </div> `); successModal.children[0].style.padding = "8dvmin 3dvmin"; successModal.classList.add("Ihatecss"); } } catch (error) { console.error("Error in transaction:", error); // Let the wallet handle error cases - don't show our own modal } }); submitInfoButton.addEventListener("click", () => { const submitInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;padding: 2dvmin 4dvmin;">While anyone may interact with this interface and attempt to submit a solution, only the wallet address registered on-chain at the time of acquisition holds the exclusive right to advance to the next phase:<br> to unlock the NFT, validate the reconstruction, and update its metadata with the recovered artwork.</div>` ); submitInfoModal.children[0].style.height = "auto"; submitInfoModal.children[0].style.width = "80dvmin"; }); viewArtworkInfoButton.addEventListener("click", () => { const viewArtworkInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;padding: 2dvmin 4dvmin;">The Physical Collector may or may not choose to make the artwork available for display</div>` ); viewArtworkInfoModal.children[0].style.height = "auto"; viewArtworkInfoModal.children[0].style.width = "80dvmin"; }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") { const modal = document.querySelector(".modal"); if (modal) closeModal(modal); } }); const collectorElements = document.querySelectorAll(".collector"); collectorElements.forEach((element) => { console.log(element.textContent); element.addEventListener("click", function () { window.open("https://etherscan.io/address/" + element.textContent, "_blank"); }); }); const timer = document.querySelector(".timer"); const targetDate = new Date("April 3, 2025 13:00:00 EDT"); const timerInterval = setInterval(() => { const now = new Date(); const timeZoneDiff = now.getTimezoneOffset() * 60000; const nowUTC = new Date(now.getTime() + timeZoneDiff); const nyTimeOffset = -4 * 60 * 60000; const nowNY = new Date(nowUTC.getTime() + nyTimeOffset); const difference = targetDate - nowNY; const years = Math.floor(Math.abs(difference) / (1000 * 60 * 60 * 24 * 365.25)); const days = Math.abs( Math.floor((difference % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24)) ); const hours = Math.abs(Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))); const minutes = Math.abs(Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60))); const seconds = Math.abs(Math.floor((difference % (1000 * 60)) / 1000)); if (difference <= 0) { timer.textContent = "ENTER"; timer.classList.add("button"); timer.addEventListener("click", enterGame); const chronometer = document.querySelector(".chronometer"); chronometer.textContent = `${padZero(years)}y:${padZero(days)}:${padZero( hours )}:${padZero(minutes)}:${padZero(seconds)}`; return; } timer.textContent = `${padZero(days)}:${padZero(hours)}:${padZero(minutes)}:${padZero( seconds )}`; }, 500); setTimeout(function () { timer.style.opacity = 1; }, 500); }; function padZero(num) { return num.toString().padStart(2, "0"); } // Simplified enterGame function let isGameEntered = false; async function enterGame() { if (isGameEntered) return; try { const provider = await getProvider(); proceedToEnterGame(provider); } catch (error) { console.error("Failed to initialize provider:", error); } } // Helper function to actually enter the game once we have a provider async function proceedToEnterGame(provider) { // Call getContractData when needed await getContractData(); document.querySelector(".background").style.opacity = 1; isGameEntered = true; const cover = document.querySelector(".cover"); const game = document.querySelector(".game"); const ending = document.querySelector(".ending"); // Target element based on the unlocked status const targetElement = isUnlocked ? ending : game; cover.style.opacity = "0"; setTimeout(() => { cover.style.display = "none"; targetElement.style.display = "flex"; targetElement.style.transition = "opacity 1s ease-in"; setTimeout(() => { targetElement.style.opacity = "1"; console.log(isUnlocked ? "ENDING REACHED" : "WELCOME"); }, 50); }, 1000); } function showModal(content) { const existingModal = document.querySelector(".modal"); if (existingModal) { existingModal.remove(); } const modal = document.createElement("div"); modal.className = "modal"; modal.innerHTML = ` <div class="modal-content"> <span class="close">&times;</span> ${content} </div> `; document.body.appendChild(modal); modal.offsetHeight; modal.style.display = "flex"; setTimeout(() => { modal.style.opacity = "1"; }, 10); const closeBtn = modal.querySelector(".close"); closeBtn.onclick = () => closeModal(modal); window.onclick = (e) => { if (e.target === modal) closeModal(modal); }; return modal; } function closeModal(modal) { modal.style.opacity = "0"; setTimeout(() => { modal.remove(); }, 300); } async function isFileCorrect() { try { const fileInput = document.querySelector("textarea"); let inputText = fileInput.value.trim(); const verificationString = document.querySelector(".verificationString"); if (!inputText) { verificationString.innerHTML = ""; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } if (inputText.startsWith("0x")) { inputText = inputText.substring(2); } if (!/^[0-9a-fA-F]*$/.test(inputText)) { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } let inputBytes; try { if (inputText.length % 2 !== 0) { inputText = "0" + inputText; } inputBytes = ethers.getBytes("0x" + inputText); } catch (e) { console.error("Error parsing hex input:", e); verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } const base64Content = ethers.encodeBase64(inputBytes); const dataURI = `data:image/jpeg;base64,${base64Content}`; const dataURIBytes = ethers.toUtf8Bytes(dataURI); const submittedFileHash = ethers.keccak256(dataURIBytes); // Store first hash as submittedFileHash const packedFirstHash = ethers.solidityPacked(["bytes32"], [submittedFileHash]); const hashedFileHash = ethers.keccak256(packedFirstHash); console.log("First hash (submittedFileHash):", submittedFileHash); console.log("Final hash (hashedFileHash):", hashedFileHash); const expectedHashedFileHash = "0xb43501f79c29086d44cc94ea56ab6c0901cbc79e113f498a64dbfde145f1fa49"; if (hashedFileHash.toLowerCase() === expectedHashedFileHash.toLowerCase()) { verificationString.innerHTML = "✓ &nbsp;Quantum state observed. Reality collapses into certainty."; document.querySelector(".submit").classList.remove("disabled"); return { dataURI, submittedFileHash }; // Return an object with the values } else { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; document.querySelector(".submit").classList.add("disabled"); return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } catch (error) { console.error("Error in isFileCorrect function:", error); document.querySelector(".verificationString").innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } function stringToHexBytes(str) { return Array.from(new TextEncoder().encode(str)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } document.addEventListener("DOMContentLoaded", function () { const fileInput = document.querySelector("textarea"); const textareaContainer = document.querySelector(".textareaContainer"); let debounceTimer; fileInput.addEventListener("input", function () { clearTimeout(debounceTimer); debounceTimer = setTimeout(function () { isFileCorrect(); }, 300); }); fileInput.addEventListener("paste", function () { setTimeout(isFileCorrect, 50); }); ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ["dragenter", "dragover"].forEach((eventName) => { textareaContainer.addEventListener(eventName, highlight, false); }); ["dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, unhighlight, false); }); function highlight() { textareaContainer.style.backgroundColor = "#e6e3dc"; } function unhighlight() { textareaContainer.style.backgroundColor = "#f7f6f3"; } textareaContainer.addEventListener("drop", handleDrop, false); function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; if (files.length > 0) { const file = files[0]; readFileAsHex(file); } } function readFileAsHex(file) { const reader = new FileReader(); reader.onload = function (e) { const arrayBuffer = e.target.result; const bytes = new Uint8Array(arrayBuffer); let hexString = ""; for (let i = 0; i < bytes.length; i++) { const hex = bytes[i].toString(16).padStart(2, "0"); hexString += hex; } fileInput.value = hexString; isFileCorrect(); }; reader.readAsArrayBuffer(file); } }); // Add contract details const VAULT_ADDRESS = "0x24e9C8Aa584F7F0338ec617E3F2261F4BdC49708"; // TODO: UPDATE THIS const VAULT_ABI = [ "function physicalCollectorAddress() view returns (address)", "function isUnlocked() view returns (bool)", "function unlockAddress() view returns (address)", "function unlockTimestamp() view returns (uint256)", "function owner() view returns (address)", "function fileAddress() view returns (address)", "function isFileCorrect(address potentialFileAddress) view returns (bool, string)", "function unlockNFT(bytes32 submittedFileHash) external", ]; async function getProvider() { let provider; try { // TODO: REMOVE localhost when deploying provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com"); //provider = new ethers.JsonRpcProvider("http://localhost:8545"); await provider.getBlockNumber(); // Test the connection console.log("Connected to public RPC provider"); return provider; } catch (error) { console.warn("Public RPC failed:", error); if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); console.log("Connected using wallet"); return provider; } catch (err) { console.error("User rejected wallet connection:", err); throw new Error("Failed to connect to wallet"); } } throw new Error("No provider available"); } } // Update getContractData to use the centralized provider async function getContractData() { try { const provider = await getProvider(); const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, provider); const collectorAddress = await vaultContract.physicalCollectorAddress(); console.log("physicalCollectorAddress: " + collectorAddress); // Update first collector address element const collectorElement = document.querySelector(".collector"); if (collectorElement) { collectorElement.textContent = collectorAddress; } // Get vault unlock status isUnlocked = await vaultContract.isUnlocked(); console.log("isUnlocked: " + isUnlocked); // Variables to store file data let fileAddress = null; let jpegDataURI = null; // If the vault is unlocked, get the unlock details from state variables if (isUnlocked) { try { // Get unlock information directly from state variables const unlockAddress = await vaultContract.unlockAddress(); const unlockTimestamp = await vaultContract.unlockTimestamp(); console.log("Unlock address:", unlockAddress); console.log("Unlock timestamp:", unlockTimestamp); if (unlockTimestamp > 0) { // Check if the timestamp is valid // Convert timestamp to date const unlockDate = new Date(Number(unlockTimestamp) * 1000); console.log("Unlock date:", unlockDate.toISOString()); // Update the chronometer with the unlock timestamp const chronometer = document.querySelector(".ending .chronometer"); if (chronometer) { chronometer.textContent = `${unlockDate .getUTCDate() .toString() .padStart(2, "0")}/${(unlockDate.getUTCMonth() + 1) .toString() .padStart(2, "0")}/${unlockDate.getUTCFullYear()}`; } // Update the collector in the ending screen with unlock address const endingCollector = document.querySelector(".ending .collector"); if (endingCollector) { endingCollector.textContent = unlockAddress; } fileAddress = await vaultContract.fileAddress(); console.log("File address:", fileAddress); try { // First check if the file is correct using the Vault contract's isFileCorrect function const [isCorrect, fileContent] = await vaultContract.isFileCorrect(fileAddress); console.log("File correctness check:", isCorrect); if (isCorrect && fileContent) { jpegDataURI = fileContent; console.log("Retrieved verified JPEG data URI successfully"); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { viewArtworkButton.addEventListener("click", function () { showModal(` <div style="text-align:center;"> <div class="modal-title">QUANTUM HEX MACHINA</div> <div class="modal-subtitle">THE UNLOCKED ARTWORK</div> <div style="margin-top: 2dvmin;"> <img src="${jpegDataURI}" style="max-width: 90%; max-height: 70dvmin;" alt="Quantum Hex Machina" /> </div> </div> `); }); viewArtworkButton.classList.remove("disabled"); console.log("View Artwork button enabled"); } } else { console.log("File verification failed"); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { // Simply keep the button disabled by adding the disabled class viewArtworkButton.classList.add("disabled"); console.log("View Artwork button disabled due to file verification failure"); } } } catch (error) { console.error("Error verifying file:", error); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { // Also keep the button disabled in case of errors viewArtworkButton.classList.add("disabled"); console.log("View Artwork button disabled due to verification error"); } } } else { console.log("No unlock data found despite unlocked status"); // Set default values for testing if no timestamp const chronometer = document.querySelector(".chronometer"); if (chronometer) { chronometer.textContent = "UNLOCKED"; } } } catch (error) { console.error("Error getting unlock details:", error); } } return { collectorAddress, isUnlocked, unlockAddress: await vaultContract.unlockAddress(), unlockTimestamp: await vaultContract.unlockTimestamp(), fileAddress, jpegDataURI, }; } catch (error) { console.error("Error fetching contract data:", error); } } </script> <style> html { background-color: black; width: 100%; height: 100%; color: #6e6d69; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: "Times New Roman", serif; font-weight: 500; margin: 0; padding: 0; background-color: #ece9e2; background-image: url("https://arweave.net/0MD2DIp1YxwVD1xATJssXH54S9Xjz2lXA583PogfmpY"); background-size: cover; background-position: center; background-repeat: no-repeat; } body { display: flex; flex-direction: column; width: 100dvmin; height: 100dvmin; align-items: center; justify-content: center; text-align: center; margin: 0; padding: 0; } .background { width: 100%; height: 100%; position: absolute; background-color: #ece9e2; opacity: 0; transition: opacity 1s; } .main { display: flex; flex-direction: column; align-items: center; gap: 1.3dvmin; transition: opacity 1s ease-in-out; margin-bottom: 0.4dvmin; z-index: 10; } .ending { margin-bottom: 6.5dvmin; display: none; opacity: 0; gap: 4dvmin; } .game { margin-bottom: 6.5dvmin; display: none; opacity: 0; gap: 4dvmin; } .title { font-size: 2.5dvmin; letter-spacing: 0.54dvmin; text-indent: 0.54dvmin; } .subtitle { letter-spacing: 0.225dvmin; text-indent: 0.225dvmin; font-size: 1dvmin; } .timer { background-color: #3e3e3e; color: #ece9e2; padding: 0.8dvmin 1.5dvmin; border-radius: 2dvmin; font-size: 1.2dvmin; transform: translateY(0.7dvmin); letter-spacing: 0.24dvmin; text-indent: 0.24dvmin; leading-trim: both; opacity: 0; transition: 1.5s opacity; } .Ihatecss { font-family: "Times New Roman", serif !important; } .button { background-color: #3e3e3e; leading-trim: both; color: #ece9e2; font-size: 1.2dvmin; padding: 0.8dvmin 1.5dvmin; border-radius: 2dvmin; cursor: pointer; transition: opacity 1.5s ease-in-out, background-color 0.1s; user-select: none; letter-spacing: 0.24dvmin; text-indent: 0.24dvmin; } .button:hover { background-color: #6e6d69; } .disabled { background-color: #aeaeae; cursor: default; } .disabled:hover { background-color: #aeaeae; } .info { padding: 0.8dvmin 2.4dvmin; margin-top: 2.2dvmin; } .titleContainer { display: flex; flex-direction: column; align-items: center; gap: 1.1dvmin; } .titleContainer > .title { font-size: 1.7dvmin; } .titleContainer > .subtitle { font-size: 0.7dvmin; } .inputContainer { display: flex; flex-direction: column; align-items: center; position: relative; } .textareaContainer { width: 48dvmin; display: flex; position: relative; background-color: #f7f6f3; padding: 2dvmin; padding-bottom: 9.5dvmin; align-items: center; justify-content: center; flex-direction: column; } .ending .textareaContainer { height: 48.5dvmin; } .ending .chronometerContainer { position: initial; bottom: initial; padding: 0.8dvmin 3dvmin; } .ending .collectorContainer { align-items: center; } .ending .collector { font-size: 1.2dvmin; } textarea { width: 100%; height: 48.5dvmin; background-color: #f7f6f3; font: inherit; font-size: 1.1dvmin; line-height: 1.1dvmin; color: inherit; vertical-align: top; letter-spacing: 0.18dvmin; text-align: justify; outline: none; border: none; box-shadow: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; resize: none; overflow-y: scroll; scrollbar-gutter: stable; overflow-x: auto; overflow-y: overlay; scrollbar-width: none; font-family: "Calibri", "Open Sans", sans-serif; font-family: monospace; } textarea::placeholder { color: #e0ddd7; } textarea::-webkit-scrollbar-track { background: transparent; } textarea { scrollbar-color: rgba(110, 109, 105, 0.5) transparent; } .chronometerContainer { position: absolute; bottom: 7.5dvmin; padding: 0.8dvmin 8dvmin; background-color: #e6e3dc; border-radius: 8dvmin; display: flex; flex-direction: column; gap: 0.2dvmin; } .verificationString { position: absolute; bottom: 13.5dvmin; font-size: 1.1dvmin; font-family: "Calibri", "Open Sans", sans-serif; background-color: #f7f6f3; } .submitInfo { position: absolute; bottom: 4dvmin; right: -2.8dvmin; line-height: 1.6dvmin; width: 1.6dvmin; height: 1.6dvmin; border-radius: 50%; color: #6f6d69; border: solid 0.15dvmin #6f6d69; font-weight: 200; font-family: sans-serif; font-size: 1.5dvmin; cursor: pointer; } .submitInfo:hover { opacity: 0.75; } .viewArtworkInfo { position: absolute; bottom: 0.5dvmin; right: 11dvmin; line-height: 1.6dvmin; width: 1.6dvmin; height: 1.6dvmin; border-radius: 50%; color: #6f6d69; border: solid 0.15dvmin #6f6d69; font-weight: 200; font-family: sans-serif; font-size: 1.5dvmin; cursor: pointer; } .viewArtworkInfo:hover { opacity: 0.75; } .collectorContainer { display: flex; flex-direction: column; justify-content: flex-start; width: 100%; align-items: start; margin-top: 1dvmin; margin-left: 0.6dvmin; gap: 0.3dvmin; } .collector { font-weight: bold; text-decoration: underline; letter-spacing: 0.22dvmin; cursor: pointer; } .collector:hover { opacity: 0.6; } .collectorTitle { letter-spacing: 0.08dvmin; font-size: 0.9dvmin; } .submit { align-self: end; border-radius: 0; } .viewArtwork { border-radius: 0; align-self: center; } .chronometer { font-size: 1.8dvmin; } .modal { position: fixed; z-index: 100; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.3); opacity: 0; transition: opacity 0.3s ease-in-out; font-family: "Calibri", "Open Sans", sans-serif; display: flex; justify-content: center; align-items: center; font-size: 1.2dvmin; } .modal-content { background-color: #f7f6f3; padding: 3dvmin; width: 85dvmin; position: relative; border-radius: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; } .text-center { text-align: center; } .modal-title { font-size: 1.45dvmin; text-align: center; margin-top: 0; font-weight: 600; color: #3e3e3e; } .modal-subtitle { font-size: 1.27dvmin; text-align: center; margin-top: 0; margin-bottom: 3dvmin; font-weight: normal; color: #3e3e3e; } .modal-body { line-height: 1.8; color: #3e3e3e; text-align: left; padding: 0 10dvmin; } .close { color: #6e6d69; position: absolute; right: 0.75dvmin; top: 0.25dvmin; font-size: 2dvmin; font-weight: bold; cursor: pointer; padding: 0.5dvmin; user-select: none; } .close:hover { opacity: 0.7; } </style> <body> <div class="background"></div> <div class="main cover"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="timer">00:00:00:00</div> </div> <div class="main game"> <div class="titleContainer"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="info button">INFO</div> </div> <div class="inputContainer"> <div class="textareaContainer"> <textarea type="text" placeholder="Paste correct string here/drag in to upload a file" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" ></textarea> </div> <div class="verificationString"></div> <div class="chronometerContainer"> <div class="subtitle">UNSOLVED SINCE</div> <div class="chronometer title">00:00:00:00</div> </div> <div class="submit button disabled">SUBMIT</div> <div class="submitInfo">i</div> <div class="collectorContainer"> <div class="subtitle collectorTitle"> PHYSICAL ART COLLECTOR / WALLET ALLOWED TO CLAIM </div> <div class="subtitle collector">0x0000000000000000000000000000000000000000</div> </div> </div> </div> <div class="main ending"> <div class="titleContainer"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="info button">INFO</div> </div> <div class="inputContainer"> <div class="textareaContainer"> <div class="chronometerContainer"> <div class="subtitle">THIS ARTWORK HAS BEEN UNLOCKED</div> <div class="chronometer title">00/00/00</div> </div> <div class="collectorContainer"> <div class="subtitle collectorTitle">UNLOCKED BY</div> <div class="subtitle collector">0x0000000000000000000000000000000000000000</div> </div> </div> <div class="viewArtwork button">VIEW UNLOCKED ARTWORK</div> <div class="viewArtworkInfo">i</div> </div> </div> </body> </html>
description.txt-1**PLEASE READ CAREFULLY**\n\n𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀 is both a cryptographic puzzle and a conceptual artwork that challenges the boundaries of technology, ownership, and autonomy. \n\nAn encrypted image suspended in cryptographic limbo, a sealed contract, a puzzle of near-infinite complexity. This NFT is an access portal to a digital artwork that cannot be viewed — not yet.\n\nThe image has been scrambled at the byte level using arithmetic JPEG encoding. Its hexadecimal order is broken, but its soul remains intact — waiting to be reassembled.\n\nExclusive access to the full scrambled string is granted to the holder of the physical piece, together with technical instructions and an off-chain verification script, all included in a physical dossier delivered upon acquisition.\n \nDISCLAIMER: \nThis challenge is beyond the reach of traditional computing. Solving it may require quantum-level processing power. \n\nThis NFT functions as a certificate of ownership for the physical artwork, tying the collector’s wallet address to the tangible piece and granting exclusive rights to eventually unlock, claim, and complete the digital artwork.\n\nIn the meantime, the collector will hold something just as rare:\nA unique physical artwork that serves as a vessel, a printed embodiment of an unsolved digital riddle. Whether the puzzle is solved tomorrow or in a hundred years, their piece will remain: a rare artifact from a world in transition. A relic of the future — waiting to be unlocked.\n\nIf Deus ex Machina once symbolized divine intervention to resolve the unsolvable — has technology now taken its place, becoming our Machina Hex Machina?\n\n*** Smart contract by Nahiko ***\n\nPLEASE NOTE: This artwork cannot be acquired via direct offer on the NFT, as it is currently locked within a smart contract. To inquire about acquiring the physical piece and its dossier — and to become the sole custodian eligible to unlock the NFT — please contact: offline@superrare.com
0x3830b0a7…09f9·#22,183,283·0x2bf49d03…915404
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_"animation_url":"data:text/html;base64,data:application/json;base64,QUANTUM_HEX_MACHINA.jpg
0x3830b0a7…09f9·#22,076,386·0x2fffb68b…6f1828
Extension already initializedAdminControl: Must be owner or a`@https://arweave.net/9RYGaR6dxYCngsWIZzJBXCR5AkJIhT3hWdK_kdBVcoA