diff --git a/app/package-lock.json b/app/package-lock.json index fcb4b54..69a3563 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -8,8 +8,10 @@ "name": "app", "version": "0.0.0", "dependencies": { + "framer-motion": "^11.2.13", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" }, "devDependencies": { "@types/react": "^18.3.3", @@ -22,7 +24,7 @@ "eslint-plugin-react-refresh": "^0.4.7", "postcss": "^8.4.38", "tailwindcss": "^3.4.4", - "vite": "^5.3.1" + "vite": "^5.3.3" } }, "node_modules/@alloc/quick-lru": { @@ -993,6 +995,14 @@ "node": ">=14" } }, + "node_modules/@remix-run/router": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", + "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.18.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", @@ -2649,6 +2659,30 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "11.2.13", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.2.13.tgz", + "integrity": "sha512-AyIeegfkXlkX1lWEudRYsJlC+0A59cE8oFK9IsN9bUQzxLwcvN3AEaYaznkELiWlHC7a0eD7pxsYQo7BC05S5A==", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3955,9 +3989,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", "dev": true, "funding": [ { @@ -3975,7 +4009,7 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "source-map-js": "^1.2.0" }, "engines": { @@ -4207,6 +4241,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", + "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", + "dependencies": { + "@remix-run/router": "1.17.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", + "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", + "dependencies": { + "@remix-run/router": "1.17.1", + "react-router": "6.24.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -4899,6 +4963,11 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5057,13 +5126,13 @@ "dev": true }, "node_modules/vite": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.1.tgz", - "integrity": "sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.3.tgz", + "integrity": "sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.38", + "postcss": "^8.4.39", "rollup": "^4.13.0" }, "bin": { diff --git a/app/package.json b/app/package.json index 1f7eb81..8281467 100644 --- a/app/package.json +++ b/app/package.json @@ -10,8 +10,10 @@ "preview": "vite preview" }, "dependencies": { + "framer-motion": "^11.2.13", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" }, "devDependencies": { "@types/react": "^18.3.3", @@ -24,6 +26,6 @@ "eslint-plugin-react-refresh": "^0.4.7", "postcss": "^8.4.38", "tailwindcss": "^3.4.4", - "vite": "^5.3.1" + "vite": "^5.3.3" } } diff --git a/app/src/App.jsx b/app/src/App.jsx index fdd42e3..06cdba2 100644 --- a/app/src/App.jsx +++ b/app/src/App.jsx @@ -1,10 +1,13 @@ +import MandelbrotFractal from "./Mandelbot" +import Blockchain from "./blockchain" +import TransactionMine from "./transactionMine" +import BlockMine from "./blockMine" import MandelbrotFractal from "./components/Mandelbrot.jsx" import JigsawGame from './components/Jigsaw.jsx'; export default function App() { return (
-
) } \ No newline at end of file diff --git a/app/src/Blockchain.css b/app/src/Blockchain.css new file mode 100644 index 0000000..7e45d79 --- /dev/null +++ b/app/src/Blockchain.css @@ -0,0 +1,6 @@ +@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); + +@tailwind base; +@tailwind components; +@tailwind utilities; + diff --git a/app/src/Scripts/vignetteCypher.js b/app/src/Scripts/vignetteCypher.js new file mode 100644 index 0000000..e69de29 diff --git a/app/src/blockMine.jsx b/app/src/blockMine.jsx new file mode 100644 index 0000000..28d02c3 --- /dev/null +++ b/app/src/blockMine.jsx @@ -0,0 +1,288 @@ +import React, { useEffect, useState } from 'react'; +import "./Blockchain.css"; + +function sha256(ascii) { + function rightRotate(value, amount) { + return (value>>>amount) | (value<<(32 - amount)); + }; + + var mathPow = Math.pow; + var maxWord = mathPow(2, 32); + var lengthProperty = 'length' + var i, j; // Used as a counter across the whole file + var result = '' + + var words = []; + var asciiBitLength = ascii[lengthProperty]*8; + + //* caching results is optional - remove/add slash from front of this line to toggle + // Initial hash value: first 32 bits of the fractional parts of the square roots of the first 8 primes + // (we actually calculate the first 64, but extra values are just ignored) + var hash = sha256.h = sha256.h || []; + // Round constants: first 32 bits of the fractional parts of the cube roots of the first 64 primes + var k = sha256.k = sha256.k || []; + var primeCounter = k[lengthProperty]; + /*/ + var hash = [], k = []; + var primeCounter = 0; + //*/ + + var isComposite = {}; + for (var candidate = 2; primeCounter < 64; candidate++) { + if (!isComposite[candidate]) { + for (i = 0; i < 313; i += candidate) { + isComposite[i] = candidate; + } + hash[primeCounter] = (mathPow(candidate, .5)*maxWord)|0; + k[primeCounter++] = (mathPow(candidate, 1/3)*maxWord)|0; + } + } + + ascii += '\x80' // Append Ƈ' bit (plus zero padding) + while (ascii[lengthProperty]%64 - 56) ascii += '\x00' // More zero padding + for (i = 0; i < ascii[lengthProperty]; i++) { + j = ascii.charCodeAt(i); + if (j>>8) return; // ASCII check: only accept characters in range 0-255 + words[i>>2] |= j << ((3 - i)%4)*8; + } + words[words[lengthProperty]] = ((asciiBitLength/maxWord)|0); + words[words[lengthProperty]] = (asciiBitLength) + + // process each chunk + for (j = 0; j < words[lengthProperty];) { + var w = words.slice(j, j += 16); // The message is expanded into 64 words as part of the iteration + var oldHash = hash; + // This is now the undefinedworking hash", often labelled as variables a...g + // (we have to truncate as well, otherwise extra entries at the end accumulate + hash = hash.slice(0, 8); + + for (i = 0; i < 64; i++) { + var i2 = i + j; + // Expand the message into 64 words + // Used below if + var w15 = w[i - 15], w2 = w[i - 2]; + + // Iterate + var a = hash[0], e = hash[4]; + var temp1 = hash[7] + + (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) // S1 + + ((e&hash[5])^((~e)&hash[6])) // ch + + k[i] + // Expand the message schedule if needed + + (w[i] = (i < 16) ? w[i] : ( + w[i - 16] + + (rightRotate(w15, 7) ^ rightRotate(w15, 18) ^ (w15>>>3)) // s0 + + w[i - 7] + + (rightRotate(w2, 17) ^ rightRotate(w2, 19) ^ (w2>>>10)) // s1 + )|0 + ); + // This is only used once, so *could* be moved below, but it only saves 4 bytes and makes things unreadble + var temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) // S0 + + ((a&hash[1])^(a&hash[2])^(hash[1]&hash[2])); // maj + + hash = [(temp1 + temp2)|0].concat(hash); // We don't bother trimming off the extra ones, they're harmless as long as we're truncating when we do the slice() + hash[4] = (hash[4] + temp1)|0; + } + + for (i = 0; i < 8; i++) { + hash[i] = (hash[i] + oldHash[i])|0; + } + } + + for (i = 0; i < 8; i++) { + for (j = 3; j + 1; j--) { + var b = (hash[i]>>(j*8))&255; + result += ((b < 16) ? 0 : '') + b.toString(16); + } + } + return result; +}; + + +const BlockMine = () => { + const [minedSuccesfully, setMinedSuccessfully] = useState('') + const [pvtKey, setPvtKey] = useState('') + const [inputPubKey, setInputPubKey] = useState(''); + const [InputBlockNonce, setInputBlockNonce] = useState(''); + const [finalBlockNonce, setFinalBlockNonce] = useState('') + const [initialBlockNonce, setInitialBlockNonce] = useState(''); + const [duration, setDuration] = useState(0); + + const pushTodb = () => { + const initialTimestamp = JSON.parse(localStorage.getItem('initialTimestamp')); + const finalTimestamp = Math.floor(Date.now() / 1000); + setDuration(finalTimestamp - parseInt(initialTimestamp)); + console.log("Duration:", duration) + } + + useEffect(() => { + const savedData = JSON.parse(localStorage.getItem('pvtKey')); + if (savedData) { + setPvtKey(savedData); + } + + const savedData2 = JSON.parse(localStorage.getItem('initialBlockNonce')); + if (savedData2) { + setInitialBlockNonce(savedData2); + } + + const fetchFinalBlockNonce = () => { + let savedData3 = JSON.parse(localStorage.getItem('finalBlockNonce')); + if (!savedData3 || savedData3.trim().length === 0) { + let generatedFinalNonce = generateBlockNonce(initialBlockNonce); + localStorage.setItem('finalBlockNonce', JSON.stringify(generatedFinalNonce)); + } + savedData3 = JSON.parse(localStorage.getItem('finalBlockNonce')); + setFinalBlockNonce(savedData3); + }; + fetchFinalBlockNonce(); + + + }, [initialBlockNonce]) + + const pubKeyDerivation = (pvtKey) => { + let pvtKeySplit = pvtKey.toLowerCase().split(''); + let toNum = ""; + for (let i = 0; i < pvtKeySplit.length; i++) { + if (pvtKeySplit[i].match(/[a-z]/i)){ + toNum += (pvtKeySplit[i].charCodeAt(0) - 96).toString(); + } else { + toNum += pvtKeySplit[i]; + } + } + toNum = parseInt(toNum); + + toNum *= 1729; + toNum = toNum % 1000000000; + toNum = toNum.toString().split(''); + let pubKey = []; + for (let i = 0; i < toNum.length; i++) { + if (parseInt(toNum[i]) % 2 !== 0) { + pubKey.push(String.fromCharCode(parseInt(toNum[i]) + 96)); + } else { + pubKey.push(toNum[i]); + } + } + return pubKey.join(''); + } + + const pubKey = pubKeyDerivation(pvtKey); + + const generateBlockNonce = (lastBlockNonce) => { + let lastBlockNonceM = lastBlockNonce.split(''); + let letters = ''; + let numbers = ''; + for (let i = 0; i < lastBlockNonceM.length; i++) { + if (lastBlockNonceM[i].match(/[a-z]/i)) { + letters += lastBlockNonceM[i]; + } else { + numbers += lastBlockNonceM[i]; + } + } + let newNonce = caeserCipher(letters, 3) + numbers; + console.log(sha256(newNonce)) + return sha256(newNonce); + + } + + // caeser cipher used in the final nonce generation + function caeserCipher(str, num) { + num = num % 26; + let lowerCaseString = str.toLowerCase(); + let alphabet = 'abcdefghijklmnopqrstuvwxyz'.split(''); + let newString = ''; + for (let i = 0; i < lowerCaseString.length; i++) { + let currentLetter = lowerCaseString[i]; + if (currentLetter === ' ') { + newString += currentLetter; + continue; + } + let currentIndex = alphabet.indexOf(currentLetter); + let newIndex = currentIndex + num; + if (newIndex > 25) newIndex = newIndex - 26; + if (newIndex < 0) newIndex = 26 + newIndex; + if (str[i] === str[i].toUpperCase()) { + newString += alphabet[newIndex].toUpperCase(); + } else newString += alphabet[newIndex]; + } + return newString; + } + + + const handleSubmit = (e) => { + e.preventDefault(); + if (inputPubKey === pubKeyDerivation(pvtKey) && InputBlockNonce === finalBlockNonce) { + setMinedSuccessfully("Successfull"); + pushTodb(); + } else { + setMinedSuccessfully("Failed"); + } + console.log("Mining:", minedSuccesfully); + } + + return ( +
+ { minedSuccesfully !== "Successfull" && ( +
+
+

Mine Block

+

{finalBlockNonce}

+

{pubKey}

+
+ +
+ + setInputBlockNonce(e.target.value)} + > +
+ + +
+ + setInputPubKey(e.target.value)} + > +
+ +
+ + +
+ +
+ + +
+ +
+
+
+ )} + + { minedSuccesfully === "Failed" && ( +
+
+

Wrong Public Key or Block Nonce, try again...

+
+
+ )} + + { minedSuccesfully === "Successfull" && ( +
+
+

Details Correct...

+

Waiting for confirmation

+
+
+ + )} + +
+ ) +} + +export default BlockMine; \ No newline at end of file diff --git a/app/src/blockchain.jsx b/app/src/blockchain.jsx new file mode 100644 index 0000000..854847a --- /dev/null +++ b/app/src/blockchain.jsx @@ -0,0 +1,113 @@ +import React, { useEffect, useState } from 'react'; +import { AnimatePresence, motion } from 'framer-motion'; +import "./Blockchain.css"; + +const Blockchain = () => { + const [isOpen, setIsOpen] = useState(true); // State to control the flap + const [isPaperVisible, setIsPaperVisible] = useState(false); + const [pvtKey, setPvtKey] = useState(''); // State to store the private key + + + // Generate a random pvt key + const genPvtKey = (length) => { + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + let counter = 0; + while (counter < length) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + counter += 1; + } + return result; + + + } + + // useEffect with an empty dependency array to run only once after the initial render + useEffect(() => { + + let savedData = JSON.parse(localStorage.getItem('pvtKey')); + if (!savedData || savedData.trim().length === 0) { + let generatedPvtKey = genPvtKey(10); + localStorage.setItem('pvtKey', JSON.stringify(generatedPvtKey)); + } + savedData = JSON.parse(localStorage.getItem('pvtKey')); + setPvtKey(savedData); + + let savedData2 = JSON.parse(localStorage.getItem('initialTimestamp')); + if (!savedData2 ) { + let initialTimestamp = Math.floor(Date.now() / 1000); + localStorage.setItem('initialTimestamp', JSON.stringify(initialTimestamp)); + } + }, []); + + const flapVariants = { + closed: { + translateY: "-100%", + rotateX: 0, + originY: 1 + }, + open: { + translateY: "-100%", + rotateX: -180, + originY: 1 + } + }; + + // Function to toggle the envelope flap state + const toggleFlap = () => { + setIsOpen(!isOpen); + if (isOpen) { + // Reset paper animation when flap closes + setIsPaperVisible(true); + } + }; + + function handleClick() { + navigate('/blockMine?pvtKey=${pvtKey}'); + } + + return ( +
+ +
{/* Add onClick event here */} + {/* Flap with animation */} + { + // Trigger paper animation only when flap opens + if (isOpen) setIsPaperVisible(false); + }} + /> + {/* Body */} +
+
+ + {/* Paper */} + + {isPaperVisible && ( + +

Private Key-

+

{pvtKey}

+
+ )} +
+ +
+
+ ); +}; + +export default Blockchain; \ No newline at end of file diff --git a/app/src/main.jsx b/app/src/main.jsx index 77429f8..b7db21a 100644 --- a/app/src/main.jsx +++ b/app/src/main.jsx @@ -7,7 +7,9 @@ import Window from './components/Window.jsx' ReactDOM.createRoot(document.getElementById('root')).render( - <> - - + + <> + + + ) diff --git a/app/src/transactionMine.jsx b/app/src/transactionMine.jsx new file mode 100644 index 0000000..721cdbf --- /dev/null +++ b/app/src/transactionMine.jsx @@ -0,0 +1,221 @@ +import React, { useEffect, useState } from 'react'; +import "./Blockchain.css"; + + +const TransactionMine = () => { + + const frameRuleTime = 10; + + const [pvtKey, setPvtKey] = useState(''); // State to store the private key + const [transaction, setTransaction] = useState(''); // State to store the transaction + const [timeLeft, setTimeLeft] = useState(60000000); + const [inputPubKey, setInputPubKey] = useState(''); + const [initialBlockNonce, setInitialBlockNonce] = useState(''); // State to store the block nonce + + // Read cookies + useEffect(() => { + const savedData = JSON.parse(localStorage.getItem('pvtKey')); + if (savedData) { + setPvtKey(savedData); + } + + + let savedData2 = JSON.parse(localStorage.getItem('initialBlockNonce')); + if (!savedData2 || savedData2.trim().length === 0) { + let generatedInitialNonce = genInitialNonce(); + localStorage.setItem('initialBlockNonce', JSON.stringify(generatedInitialNonce)); + } + savedData2 = JSON.parse(localStorage.getItem('initialBlockNonce')); + setInitialBlockNonce(savedData2); + + // Exit early when we reach 0 + if (timeLeft === 0) return; + + // Save intervalId to clear the interval when the component re-renders + const intervalId = setInterval(() => { + setTimeLeft(timeLeft - 1); + }, 1000); + + // Clear interval on re-render to avoid memory leaks + return () => clearInterval(intervalId); + // Add timeLeft as a dependency to re-run the effect when we update it + + }, [timeLeft]); + + const pubKeyDerivation = (pvtKey) => { + let pvtKeySplit = pvtKey.toLowerCase().split(''); + let toNum = ""; + for (let i = 0; i < pvtKeySplit.length; i++) { + if (pvtKeySplit[i].match(/[a-z]/i)){ + toNum += (pvtKeySplit[i].charCodeAt(0) - 96).toString(); + } else { + toNum += pvtKeySplit[i]; + } + } + toNum = parseInt(toNum); + + toNum *= 1729; + toNum = toNum % 1000000000; + toNum = toNum.toString().split(''); + let pubKey = []; + for (let i = 0; i < toNum.length; i++) { + if (parseInt(toNum[i]) % 2 !== 0) { + pubKey.push(String.fromCharCode(parseInt(toNum[i]) + 96)); + } else { + pubKey.push(toNum[i]); + } + } + return pubKey.join(''); + } + + const pubKey = pubKeyDerivation(pvtKey); + + // function to generate the nonce shown after teh transaction is completed + const genInitialNonce = () => { + const date = new Date(); + var seed = date.getDate(); + + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + let counter = 0; + let result = ''; + while (counter < 16) { + result += characters.charAt(Math.floor(seededRandom(seed + counter) * charactersLength)); + counter += 1; + } + console.log(result) + return result; + } + + // Function to generate a random number from a seed + function seededRandom(seed) { + var x = Math.sin(seed++) * 10000; + return x - Math.floor(x); + } + + const handleSubmit = (e) => { + e.preventDefault(); + if (inputPubKey === pubKeyDerivation(pvtKey)) { + setTransaction("Successfull"); + setTimeLeft(frameRuleTime - (Math.floor(Date.now() / 1000) % frameRuleTime)) + } else { + setTransaction("Failed"); + } + console.log("Transaction: ", transaction); + } + + const handleClick = () => { + return + } + + return ( +
+ + {transaction !== "Successfull" && ( +
+

{pubKey}

+
+
+
+

Issue a transaction

+
+ {/* */} +
+
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + setInputPubKey(e.target.value)} + > +
+ +
+ + +
+ +
+
+ + { transaction === "Failed" && ( +
+

Wrong Public Key, try again...

+
+ )} + +
+
+ )} + + { transaction === "Successfull" && ( +
0 ? 'bg-red-500' : 'bg-green-500'}`}> +
+

Transaction details correct, waiting to be added to block

+

Time left: {timeLeft}

+ +
+

Block Nonce:

+ {timeLeft > 0 && ( +

░░░░░░░░░░░░░░░

+ )} + {timeLeft === 0 && ( +

{initialBlockNonce}

+ ) } +
+
+

Transaction Number:

+ {timeLeft > 0 && ( +

░░░░░░░░░░░░░░░

+ )} + {timeLeft === 0 && ( +

54150

+ ) } +
+
+

Timestamp:

+ {timeLeft > 0 && ( +

░░░░░░░░░░░░░░░

+ )} + {timeLeft === 0 && ( +

{Math.floor(Date.now() / 1000)}

+ ) } +
+ + {timeLeft === 0 && ( +
+

Congrats! You are upgraded to a miner

+ +
+ )} + +
+
+ )} + + +
+ )} + + + +export default TransactionMine; \ No newline at end of file diff --git a/app/tailwind.config.js b/app/tailwind.config.js index 343d40e..327c3aa 100644 --- a/app/tailwind.config.js +++ b/app/tailwind.config.js @@ -5,7 +5,11 @@ export default { "./src/**/*.{js,ts,jsx,tsx}", ], theme: { - extend: {}, + extend: { + fontFamily: { + retro: ['"Press Start 2P"', 'system-ui'], + } + }, }, plugins: [ ],