From 4d5582243caeeed4e43e6f81eaaf18e2eb4bd8b2 Mon Sep 17 00:00:00 2001 From: JEREMIAH PETER Date: Sat, 14 Feb 2026 19:22:00 +0100 Subject: [PATCH 1/4] feat:add all assignment --- assignments/1-block-observation/README.md | 53 --- assignments/2-gas-hash/hash.ts | 166 -------- assignments/2-gas-hash/package-lock.json | 348 ----------------- assignments/2-gas-hash/package.json | 16 - assignments/3-block-hash/README.md | 110 ------ assignments/3-block-hash/block.json | 32 -- assignments/3-block-hash/blockHash.ts | 113 ------ assignments/3-block-hash/package-lock.json | 354 ------------------ assignments/3-block-hash/package.json | 21 -- assignments/3-block-hash/tsconfig.json | 10 - assignments/4-jsonRpc-observations/README.md | 121 ------ assignments/5-notes-on-terms/README.md | 48 --- .../6-wallet-address/package-lock.json | 328 ---------------- assignments/assign1/README.md | 32 ++ assignments/{2-gas-hash => assign2}/README.md | 0 assignments/assign2/calgas.js | 28 ++ assignments/assign2/calgas.md | 109 ++++++ assignments/assign2/mkroot.js | 213 +++++++++++ assignments/assign2/package.json | 6 + assignments/assign3/ETHSUM.md | 91 +++++ assignments/assign3/blockHash.js | 23 ++ assignments/assign4/README.md | 22 ++ assignments/assign5/README.md | 55 +++ .../{6-wallet-address => assign6}/README.md | 0 .../dictionary.json | 0 .../package.json | 0 .../tsconfig.json | 0 .../wallet-address.js} | 1 - 28 files changed, 579 insertions(+), 1721 deletions(-) delete mode 100644 assignments/1-block-observation/README.md delete mode 100644 assignments/2-gas-hash/hash.ts delete mode 100644 assignments/2-gas-hash/package-lock.json delete mode 100644 assignments/2-gas-hash/package.json delete mode 100644 assignments/3-block-hash/README.md delete mode 100644 assignments/3-block-hash/block.json delete mode 100644 assignments/3-block-hash/blockHash.ts delete mode 100644 assignments/3-block-hash/package-lock.json delete mode 100644 assignments/3-block-hash/package.json delete mode 100644 assignments/3-block-hash/tsconfig.json delete mode 100644 assignments/4-jsonRpc-observations/README.md delete mode 100644 assignments/5-notes-on-terms/README.md delete mode 100644 assignments/6-wallet-address/package-lock.json create mode 100644 assignments/assign1/README.md rename assignments/{2-gas-hash => assign2}/README.md (100%) create mode 100644 assignments/assign2/calgas.js create mode 100644 assignments/assign2/calgas.md create mode 100644 assignments/assign2/mkroot.js create mode 100644 assignments/assign2/package.json create mode 100644 assignments/assign3/ETHSUM.md create mode 100644 assignments/assign3/blockHash.js create mode 100644 assignments/assign4/README.md create mode 100644 assignments/assign5/README.md rename assignments/{6-wallet-address => assign6}/README.md (100%) rename assignments/{6-wallet-address => assign6}/dictionary.json (100%) rename assignments/{6-wallet-address => assign6}/package.json (100%) rename assignments/{6-wallet-address => assign6}/tsconfig.json (100%) rename assignments/{6-wallet-address/wallet-address.ts => assign6/wallet-address.js} (99%) diff --git a/assignments/1-block-observation/README.md b/assignments/1-block-observation/README.md deleted file mode 100644 index a832de62..00000000 --- a/assignments/1-block-observation/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# The Ethereum Blockchain Explorer (Etherscan) & Transaction Hash - -## The Ethereum Blockchain Explorer (Etherscan) - -### Overview Page Observations -On the Etherscan overview homepage, I observed the following key metrics in the network: -1. **Live Ether Price**: In real-time, this displays the current price of ETH. -2. **Market Capitalization**: Represents the total value of all ETH in circulation. -3. **Transactions**: This displays the total number of transactions processed on the Ethereum network, increasing continuously as new transactions are confirmed. -4. **Last Finalized Block**: This shows us the most recent block that has achieved finality. - - -#### A table that display the lastest blocks -After clicking on the latest block at the time, there are several details I observed about the block and they are: - -1. **Block Height**: This indicates the length of the blockchain, increases after the addition of the new block. -2. **Status**: As at the time I checked it, it was finalized. This shows the status of the finality of the block. -3. **Proposed On** and **Timestamps**: Basically, this gives us information about when the transaction started. -4. Withdrawals -5. **Fee Recipient**: This gives us basic information about the receiver of the transaction. -6. **Block Reward**: This is the total reward earned from the miner. -7. Gas information -8. Block Size -9. **Extra Data**: More information about the recipient - - -#### A table that display the lastest transactions - -After clicking on the latest transaction at the time, there are several transaction details and they are: - -##### Transaction Overview -1. **Transaction Hash**: A unique 64-bit character id for ay given transaction. -2. **Status**: This shows us the progress of the transaction. -3. Block -4. Timestamp**: Giving us information about when the transaction took place. - -##### Transaction Cost Details -This gives us information about the cost of transaction like its fee and gas price. - -Etherscan serves as a powerful blockchain explorer for transparently analyzing Ethereum's blocks, transactions, and validator behavior. - -## Transaction Hash - -### Overview Page Observations - -Similar to the overview page of the etherscan of several transactions and blocks, this page gives us a keen view of the information that pertains to a particular transaction. - -We have the transaction hash of this transaction, the status, spacific block and the amount of block confirmations, timestamp from the time it was proposed (I think), the sender and receiver's wallet address, value of eth sent, transaction fee and gas price. - -There's also a button that when clicked, will show us a dropdown of more information about the transaction - -## Conclusion -In conclusion, I think the Etherscan is a powerful blockchain explorer for analyzing Etherum blocks, transactions, and validator behaviour, transparently. \ No newline at end of file diff --git a/assignments/2-gas-hash/hash.ts b/assignments/2-gas-hash/hash.ts deleted file mode 100644 index cd282994..00000000 --- a/assignments/2-gas-hash/hash.ts +++ /dev/null @@ -1,166 +0,0 @@ - -import { ethers } from "ethers"; -import * as crypto from 'crypto'; -import * as readline from 'readline-sync'; - -// Gas Price Calculation -function calculateGasFee() { - // Prompt for gas price (in Gwei) - const gasPriceGwei = parseFloat( - readline.question("Enter gas price in Gwei: "), - ); - - // Prompt for gas used (in units) - const gasUsed = parseFloat(readline.question("Enter gas used: ")); - - // Calculate total gas fee in ETH - const totalGasFee = (gasPriceGwei * gasUsed) / 1e9; // Convert Gwei to ETH - console.log(`Total Gas Fee: ${totalGasFee} ETH`); -} - -// Merkle Root Calculations - -// Helper function to hash using the SHA256 algorithm -function sha256Hash(first: Buffer, second: Buffer): string { - const combinedLeaf = Buffer.concat([first, second]); - return crypto.createHash("sha256").update(combinedLeaf).digest("hex"); - -} - -// Similarly, KACCAK256 helper function to combine two leafs -function keccak256Hash(first: Buffer, second: Buffer): string { - const combinedLeaf = Buffer.concat([first, second]); - return ethers.keccak256(combinedLeaf); -} - -// Function to build Merkle Root -function buildMerkleRoot(leaves: string[], hashFunc: (first: Buffer, second: Buffer) => string,): string { - // Check for leaves - if (leaves.length === 0) { - throw new Error("No leaves provided"); - } - - // Convert hex leaves to Buffers: So we dont have to use the 0x prefix - let level: Buffer[] = leaves.map((leaf) => Buffer.from(leaf.slice(2), "hex")); - - while (level.length > 1) { - const nextLevel: Buffer[] = []; - for (let i = 0; i < level.length; i += 2) { - const first = level[i]; - const second = i + 1 < level.length ? level[i + 1] : first; - const parentHex = hashFunc(first, second); - nextLevel.push(Buffer.from(parentHex.slice(2), "hex")); - } - // Log the current level's hashes - console.log( - "Current level hashes: ", - nextLevel.map((hash) => hash.toString("hex")), - ); - - level = nextLevel; - } - - return "Ox" + level[0].toString("hex"); -} - -// Main hash function -function shaHashingFunction() { - // Prompt User for the Number of Transactions - const numTxs = parseInt( - readline.question("Enter number of transactions: "), - 10, - ); - - // Check if the user input character (s) or a number less than 0 - if (isNaN(numTxs) || numTxs < 0) { - console.error("Invalid number"); - return; - } - - // Check if the number of transaction is equal to zero - if (numTxs === 0) { - console.error("Please input a number greater than 0"); - return; - } - - // Initiate the transaction hashes array - const transactionHashes: string[] = []; - - for (let i = 0; i < numTxs; i++) { - // Prompt the user to enter a string to generate each the transaction hash - const inputStr = readline.question( - `Enter string for transaction ${i + 1}: `, - ); - // Derive transaction hash from input string using Keccak256 (simulating tx hash derivation) - const txHash = ethers.sha256(ethers.toUtf8Bytes(inputStr)); - console.log(`Derived Tx Hash ${i + 1}: ${txHash}`); - console.log(`The length of the Tx Hash is: ${i + 1}: ${txHash.length}`); - - // Append transaction hash to the array - transactionHashes.push(txHash); - - console.log(""); - } - - // Merkle Root Calculation - const sha256Root = buildMerkleRoot(transactionHashes, sha256Hash); - console.log("\n Merkle Root with SHA256: ", sha256Root); -} - -function keccakHashingFunction() { - // Prompt User for the Number of Transactions - const numTxs = parseInt( - readline.question("Enter number of transactions: "), - 10, - ); - - // Check if the user input character (s) or a number less than 0 - if (isNaN(numTxs) || numTxs < 0) { - console.error("Invalid number"); - return; - } - - // Check if the number of transaction is equal to zero - if (numTxs === 0) { - console.error("Please input a number greater than 0"); - return; - } - - // Initiate the transaction hashes array - const transactionHashes: string[] = []; - - for (let i = 0; i < numTxs; i++) { - // Prompt the user to enter a string to generate each the transaction hash - const inputStr = readline.question( - `Enter string for transaction ${i + 1}: `, - ); - // Derive transaction hash from input string using Keccak256 (simulating tx hash derivation) - const txHash = ethers.keccak256(ethers.toUtf8Bytes(inputStr)); - console.log(`Derived Tx Hash ${i + 1}: ${txHash}`); - console.log(`The length of the Tx Hash is: ${i + 1}: ${txHash.length}`); - - // Append transaction hash to the array - transactionHashes.push(txHash); - - console.log(""); - } - - // Merkle Root Calculation - const keccak256Root = buildMerkleRoot(transactionHashes, keccak256Hash); - console.log("\n Merkle Root with Keccak256: ", keccak256Root); -} - -// Run the gas fee calculator -calculateGasFee(); - -// Run the hashing functions -shaHashingFunction(); -keccakHashingFunction(); - - - - - - - - diff --git a/assignments/2-gas-hash/package-lock.json b/assignments/2-gas-hash/package-lock.json deleted file mode 100644 index b088725f..00000000 --- a/assignments/2-gas-hash/package-lock.json +++ /dev/null @@ -1,348 +0,0 @@ -{ - "name": "2-gas-hash", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@types/node": "^25.0.9", - "crypto": "^1.0.1", - "ethers": "^6.16.0", - "readline-sync": "^1.4.10", - "ts-node": "^10.9.2" - }, - "devDependencies": { - "@types/readline-sync": "^1.4.8" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "license": "MIT" - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.0.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.9.tgz", - "integrity": "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==", - "license": "MIT", - "peer": true, - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/@types/readline-sync": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/@types/readline-sync/-/readline-sync-1.4.8.tgz", - "integrity": "sha512-BL7xOf0yKLA6baAX6MMOnYkoflUyj/c7y3pqMRfU0va7XlwHAOTOIo4x55P/qLfMsuaYdJJKubToLqRVmRtRZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "license": "MIT" - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "license": "MIT" - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "license": "MIT" - }, - "node_modules/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", - "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.", - "license": "ISC" - }, - "node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/ethers": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", - "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/ethers/node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "license": "ISC" - }, - "node_modules/readline-sync": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", - "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "license": "MIT" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "license": "MIT" - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - } - } -} diff --git a/assignments/2-gas-hash/package.json b/assignments/2-gas-hash/package.json deleted file mode 100644 index 3d505094..00000000 --- a/assignments/2-gas-hash/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "type": "module", - "scripts": { - "hash": "ts-node ./hash.ts" - }, - "dependencies": { - "@types/node": "^25.0.9", - "crypto": "^1.0.1", - "ethers": "^6.16.0", - "readline-sync": "^1.4.10", - "ts-node": "^10.9.2" - }, - "devDependencies": { - "@types/readline-sync": "^1.4.8" - } -} diff --git a/assignments/3-block-hash/README.md b/assignments/3-block-hash/README.md deleted file mode 100644 index 3971a6da..00000000 --- a/assignments/3-block-hash/README.md +++ /dev/null @@ -1,110 +0,0 @@ -Read the Mastering Ethereum book and document your findings from the first (1) and sixth (6) chapter comprehensively in a hackMD file. Mastering Bitcoin Book -Write an algorithm to derive the block hash. -Summarize what's inside a transaction. Talk about it. - -# Assignment 3 -## Chapter 1. What is Ethereum? -Ethereum is ofte described as the "world computer". -From a computer science perspective, Ethereum is a deterministic but practically unbounded state machine, consisting of a globally accessible singleton state and a virtual machine that applies changes to that state. -Ethereum is more practically described as an open-source, globally decentralized computing infrastructure that executes programs called smart contract. - -The Ethereum platform enables developers to build powerful decentralized applications with built-in economic functions. It provides high availability, auditability, transparency, and neutrality while reducing or eliminating censorship and reducing certain counterparty risks. - -**Ethereum compared to Bitcoin** - -Yes Ethereum has striking similarities to blockchain currencies that was established before it including Bitcoin and it also has a digital currency (ether), but both the purpose and the construction of Ethereum are strikingly different from those of the open blockchains that preceeded it, including Bitcoin. - -Ethereum's purpose is not primarily to be a digital currency payment network. While the digital currency ether is both integral to and necessary for the operation of Ethereum, ether is intended as a utility currency to pay for use of Ethereum platform as the worl computer. -Unlike Bitcoin, which has a very limited scripting language, Ethereum is designed to be a general-purpose, programmable blockchain that runs a virtual machine capable of executing code of arbitrary and unbounded complexity. -Ethereum can function as a general-purpose computer, where Bitcoin's Script language is intentionally constrained to simple true/false evaluation of spending conditions. - -In September 2022, Ethereum further distinguished itself from Bitcoin With **The Merge Upgrade** by transitioning its consensus model from proof of work (PoW) to proof of stake (PoS). - -**`!!! Investigate further what PoW and PoS really means`**. - -### Components of a Blockchain -The components of an open, public blockchain are (usually) as follows: -- A P2P network connecting participants and propagating transaction and blocks of verified transactions, based on a standardized "gossip" protocol -- Messages, in the formof transactios, representing state transitions -- A set of consensus rules governing what constitutes a transaction and what makes for a valid state transition -- A state machine that processes transactions according to the consensus rules -- A chain of cryptographically secured blocks that acts as a journal of all the verified and accepted state transitions -- A consensus algorithm that decentralizes control over the blockchain by forcing participants to cooperate in the enforcement of the consensus rules -- A game-theory-sound incentivization scheme (e.g., PoW costs plus block rewards) to economically secure the state machine in an open environment -- One or more open source software implementations of these components ("clients") - -Keywords like *open*, *public*, *global decentralized*, *neutral*, and *censorship resistant*, can help us to identify the important emergent characteristics of a "blockchain" system. -We can broadly categorize blockchains into permissioned versus permissionless and public and private: -**Permissionless and Permissioned**: The former is a blockchain that's accessible to anyone like Ethereum and Bitcoin. The decentralized network allows anyone to join, participate in the consensus process, and read and write data, prompting trust and transparency. -while the latter is the opposite. There's restricted access and only authorized participants can join the network and perform some actions. -**Public and Private** -Public blockchains are decentralized and open to anyone. This promotes broad participation in network activities while private blockchains limit access to a specific group of participants, often within organizations or among trusted partners. - -### The Birth of Ethereum -Why?!!! - -Ethereum's founders were thinking about a blockchain without a specific purpose, which could support a broad variety of applications by being *programmed*. The idea was that by using a genral-purpose blockchain like Ethereum, a developer could program their particular application without having to implement the underlying mechanisms of P2P networks, blockchains, consensus algorithms, and the like. - -Ethereum abstracts away those details and offeres a deterministic, secure environment for writing decentralized applications. This doesn't only make development easier but expanded the scope (what it could do) of blockchain. Hence the birth of NFTs, decentralized autonomous organizations (DAOs), which wouldn't have been feasible with earlier single-purpose blockchains. - -**`!!! What are DAOs?`**. - -### Ethereum's Stages of Development - -The four stages of Ethereum's devlopment arelisted below: - -- **Frontier (July 30, 2015):** The was block (Genesis) was mined on this day. This laid the foundation for other developers and miners by enabling the setup of mining rigs, the initiation of the ETH token trading, and testing od DApps in a minimal network setting. -Initially, the block had a gas limit of five thousand (5,000), but that was lifted in September 2015, allowing for transactions and introducing the *difficulty bomb*. -Ethereum *difficulty bomb* is a mechanism that's designed to make minimg over time, exponentially difficult, ultimately, making it infeasible. -- **Homestead (March 14, 2016):** This stage started at block 1,150,000. Although the network remained in the beta phase, Homestead made Ethereum safer and more stable through key protocol updates (EIP-2, EIP-7, and EIP-*). These upgrades enhanced developer friendliness and paved the way for further protocol improvements. -- **Metropolis (October 16, 2017):** THis stage started at block 4,370,000. This stage aimed to foster DApp creation and overall network utility. With this stage, we have optimized gas costs, enhanced security, introduced L2 scaling solutions, reduced minimg reward and so on. These improvements set the stage for Ethereum 2.0, representing the final phase of Ethereum 1.0. -- **Serenity (September 15, 2022):** Comonly known as *Ethereum 2.0*, represents a major upgrade aimed at transforming Ethereum from a PoW to a PoS consensus mechanism. Its focus is to ensure Ethereum is sustainable and capable of handling a growing number of users and applications. This stage addresses critical issues like high energy consumption and network congestion which clears the road for a more robust and efficient blockchain. This stage is divided into several substages that handled/addressed specific aspects of the network's evolution. - -**Sharding** helps Ethereum to scale by splitting the etwork into smaller, manageable pieces, which allows for more transactions per second. - -### Ethereum: A General Purpose Blockchain -The original blockchain-Bitcoin-traks the state of units of Bitcoin and their ownership. -Alternatively, it can be seen as a distributed-consensus *state machine*, where transactions cause a *global state transition*, altering the ownership of the coins. -The rules of consensus guides the state transitions, allowing all participants to eventually converge (consensus) on a common state of the system, after several blocks are mined. - -Similarly, Ethereum is also a state machine. However it distinguishes itselft by not only tracking the state of current ownership, but also traks the state of transitions of a general-purpose data store (data expressible as a *key-value tuple*). - -Like a general-purpose stored-program computer, it stores data and the code and also tracks how the data changes over time. It can load code into its state machine and run that code, storing the resulting changes in its blockchain. - -Two of the most critical differences from the most general-purpose computers are that **Ethereum state changes are governed by the rules of consensus** and that its **state is distributed globally**. - -Ethereum answers the question "**What if we could track any arbitrary state and program the state machine to create a worldwide computer operating under consensus?**" - -### Ethereum's Components -The components of a blockchain are more specifically as follows: - -- **P2P network:** Ethereum runs on the main Ethereum network, which is addressable on TCP port 30303, and runs a protocol called *`DEVp2p`*. -- **Consensus rules:** Ethereum's original protocol was *Ethash*, a PoW model defined in the reference specification: the "Yellow Paper". It then evolved to the PoS in September 2022 during The Merge upgrade. -- **Transactions:** Ethereum transactions are network messages that include (among other things) a sender, a recipient, a value, and a data payload. -- **State Machine:** Ethereum state transitions are processed by the *Ethereum Virtual Machine (EVM)*, a stack-based virtual machine that executes bytecodes (machine-language instructions). EVM programs called *smart contracts* are written in high-level languages and combiled to bytecode for execution on the EVM. -- **Data structures:** Ethereum's state is stored locally on each node as a *database* (usually Google's LevelDB), which contains the transactions and system state in a serialized hashed data structure called a *Merkle-Patricia trie*. -- **Consensus algorithm:** In PoS consensus mechanism, validators stake their cryptocurrency to earn the right to validate transactions, create new blocks, and maintain network security. -- **Economic security:** To provide security to the blockchain, Ethereum uses a PoS algorithm called Gasper. -- **Clients** - -### Ethereum and Turing Completeness -Ethereum's ability toexecute a stored program-in a state machine called the EVM-while reading and writing data to memory makes it a Turing-complete system and therefore a Universal Turing Machine (UTM). - -Ethereum's groundbreaking innovation is to combine the general-purpose computing architecture of a stored-program computer with a decentralized blockchain, thereby creating a distributed single-data (singleton) worl computer. Ethereum programs run "everywhere" yet produce a common state that is secured by the rules of consensus. - -### Implications os Turing Completeness -Turing proved that we cannot predict whether a program will terminate by simulating it on a computer. -Turing-complete systems can run in *infinite loops* - a program that does not terminate - oversimplication. - -Now, it'll be trivial to create a program that runs a loop that never ends. But, unintended never-ending loops can arise without warning due to complex interactions between the starting condition and the code. - -We can't prove/predict how long the program/smart contract will run without actually running it (What if it runs forever). Whether intentional or not, a smart contract can be created such that it runs forever when a node/client tries to validate it. - -In a world computer, a program that abuses resources gets to abuse the world's resources. How does Ethereum constrain the resources used by a smart contract if it cannot predict resource use in advance? - - - - - - - diff --git a/assignments/3-block-hash/block.json b/assignments/3-block-hash/block.json deleted file mode 100644 index 2dae48e2..00000000 --- a/assignments/3-block-hash/block.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": 1, - "height": 850000, - "size": 1456789, - - "previousBlockHash": "0x00000000000000000002a7c4b0e4e8f8c9d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5", - - "stateRoot": "0x8f9c0a1b2c3d4e5f60718293a4b5c6d7e8f90123456789abcdef0123456789ab", - - "receiptsRoot": "0xb4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a", - - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - - "difficulty": "0x2fefd8", - - "gasLimit": 30000000, - "gasUsed": 14567890, - - "baseFeePerGas": 1000000000, - - "timestamp": 1735689600, - - "extraData": "0x657468657265756d2d61737369676e6d656e74", - - "mixHash": "0x9b1c2d3e4f5061728394a5b6c7d8e9f00112233445566778899aabbccddeeff", - - "nonce": "0x000000000000abcd", - - "transactionHashes": [ - "0xa3b1c2d4e5f60718293a4b5c6d7e8f90123456789abcdef0123456789abcdef" - ] -} diff --git a/assignments/3-block-hash/blockHash.ts b/assignments/3-block-hash/blockHash.ts deleted file mode 100644 index 2a4efe9f..00000000 --- a/assignments/3-block-hash/blockHash.ts +++ /dev/null @@ -1,113 +0,0 @@ -import * as fs from 'node:fs'; -import { ethers } from 'ethers'; - -// Keccak256 helper -function keccak256Hash(first: Buffer, second: Buffer): string { - const combinedLeaf = Buffer.concat([first, second]); - return ethers.keccak256(combinedLeaf); -} - -// Merkle Root builder -function buildMerkleRoot( - leaves: string[], - hashFunc: (first: Buffer, second: Buffer) => string -): string { - if (leaves.length === 0) { - throw new Error('No leaves provided'); - } - - let level: Buffer[] = leaves.map((leaf) => Buffer.from(leaf.slice(2), 'hex')); - - while (level.length > 1) { - const nextLevel: Buffer[] = []; - - for (let i = 0; i < level.length; i += 2) { - const first = level[i]; - const second = i + 1 < level.length ? level[i + 1] : first; - const parentHex = hashFunc(first, second); - nextLevel.push(Buffer.from(parentHex.slice(2), 'hex')); - } - - console.log( - 'Current level hashes:', - nextLevel.map((hash) => hash.toString('hex')) - ); - - level = nextLevel; - } - - return '0x' + level[0].toString('hex'); -} - -// Read block.json -const data = fs.readFileSync('block.json', 'utf8'); -const blockData = JSON.parse(data); - -// Extract fields (unchanged names) -const { - version, - height, - size, - previousBlockHash, - stateRoot, - receiptsRoot, - logsBloom, - difficulty, - gasLimit, - gasUsed, - baseFeePerGas, - timestamp, - extraData, - mixHash, - nonce, - transactionHashes, -} = blockData; - -// Compute transactionsRoot -const transactionsRoot = buildMerkleRoot(transactionHashes, keccak256Hash); - -// Log block info -console.log('Block Version:', version); -console.log('Block Height:', height); -console.log('Block Size:', size); -console.log('Parent Hash:', previousBlockHash); -console.log('Transactions Root:', transactionsRoot); -console.log('Timestamp:', timestamp); -console.log('Nonce:', nonce); -console.log(''); - -// Serialize Ethereum block header -const headerBuf = Buffer.concat([ - Buffer.from(previousBlockHash.slice(2), 'hex'), - Buffer.from(stateRoot.slice(2), 'hex'), - Buffer.from(transactionsRoot.slice(2), 'hex'), - Buffer.from(receiptsRoot.slice(2), 'hex'), - Buffer.from(logsBloom.slice(2), 'hex'), - Buffer.from(difficulty.slice(2), 'hex'), - - // gas fields - Buffer.alloc(8, 0), - Buffer.alloc(8, 0), - Buffer.alloc(8, 0), -]); - -headerBuf.writeBigUInt64BE(BigInt(gasLimit), headerBuf.length - 24); -headerBuf.writeBigUInt64BE(BigInt(gasUsed), headerBuf.length - 16); -headerBuf.writeBigUInt64BE(BigInt(baseFeePerGas), headerBuf.length - 8); - -// Final header assembly -const timeBuf = Buffer.alloc(8); -timeBuf.writeBigUInt64BE(BigInt(timestamp), 0); - -const finalHeader = Buffer.concat([ - headerBuf, - timeBuf, - Buffer.from(extraData.slice(2), 'hex'), - Buffer.from(mixHash.slice(2), 'hex'), - Buffer.from(nonce.slice(2).padStart(16, '0'), 'hex'), -]); - -// Ethereum Block Hash (Keccak256) -const blockHash = ethers.keccak256(finalHeader); - -console.log('Ethereum Block Hash:', blockHash); diff --git a/assignments/3-block-hash/package-lock.json b/assignments/3-block-hash/package-lock.json deleted file mode 100644 index 621fb32f..00000000 --- a/assignments/3-block-hash/package-lock.json +++ /dev/null @@ -1,354 +0,0 @@ -{ - "name": "3-block-hash", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "3-block-hash", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "crypto": "^1.0.1", - "ethers": "^6.16.0" - }, - "devDependencies": { - "@types/node": "^25.0.10", - "ts-node": "^10.9.2" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "license": "MIT" - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz", - "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "license": "MIT" - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", - "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.", - "license": "ISC" - }, - "node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/ethers": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", - "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/ethers/node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - } - } -} diff --git a/assignments/3-block-hash/package.json b/assignments/3-block-hash/package.json deleted file mode 100644 index 9e4aebd2..00000000 --- a/assignments/3-block-hash/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "3-block-hash", - "version": "1.0.0", - "description": "Read the Mastering Ethereum book and document your findings from the first (1) and sixth (6) chapter comprehensively in a hackMD file. Mastering Bitcoin Book Write an algorithm to derive the block hash. Summarize what's inside a transaction. Talk about it.", - "main": "index.js", - "scripts": { - "blockHash": "ts-node blockHash.ts" - }, - "keywords": [], - "author": "", - "license": "ISC", - "type": "module", - "dependencies": { - "crypto": "^1.0.1", - "ethers": "^6.16.0" - }, - "devDependencies": { - "@types/node": "^25.0.10", - "ts-node": "^10.9.2" - } -} diff --git a/assignments/3-block-hash/tsconfig.json b/assignments/3-block-hash/tsconfig.json deleted file mode 100644 index 7b0fe8c5..00000000 --- a/assignments/3-block-hash/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", - "moduleResolution": "node", - "types": ["node"], - "strict": true, - "esModuleInterop": true - } -} diff --git a/assignments/4-jsonRpc-observations/README.md b/assignments/4-jsonRpc-observations/README.md deleted file mode 100644 index f27b6d26..00000000 --- a/assignments/4-jsonRpc-observations/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Ethereum JSON-RPC API - Quick Overview - -This document lists **all important JSON-RPC methods** used to talk to an Ethereum node. - -Ethereum has two main parts after The Merge (2022): - -- **Execution client** (Geth, Erigon, Nethermind, Besu, Reth...) -> handles transactions, smart contracts, EVM -- **Consensus client** (Prysm, Lighthouse, Teku, Nimbus, Lodestar...) -> handles proof-of-stake, validators, Beacon Chain - -Most people use the **Execution client JSON-RPC** (port 8545 by default) when they build dApps, wallets or scripts. -This page mainly covers **Execution client methods**. - -> Note: Consensus client has its own API called **Beacon API** (usually port 5052). -> There is also the **Engine API** (between execution ↔ consensus client), but normal developers almost never use it directly. - -## Main JSON-RPC Categories - -### 1. Web3 / Net / Client Info -Methods to check node version, network, connection status - -- web3_clientVersion -- web3_sha3 -- net_version -- net_listening -- net_peerCount -- eth_protocolVersion (not always supported) -- eth_chainId -- eth_syncing -- eth_mining (only PoW networks) -- eth_hashrate (only PoW networks) -- eth_gasPrice -- eth_accounts (only if node manages keys) -- eth_coinbase (deprecated) - -### 2. Block & Chain Head -Methods to know current block and chain status - -- eth_blockNumber -- eth_getBlockByHash -- eth_getBlockByNumber -- eth_getBlockTransactionCountByHash -- eth_getBlockTransactionCountByNumber -- eth_getUncleCountByBlockHash -- eth_getUncleCountByBlockNumber - -### 3. Account & Balance -Check balances, nonce, code, storage - -- eth_getBalance -- eth_getTransactionCount -- eth_getCode -- eth_getStorageAt - -### 4. Transaction Sending -Send / sign transactions - -- eth_sendTransaction -- eth_sendRawTransaction -- eth_sign (dangerous – only for testing) -- eth_signTransaction (signs but does not send) - -### 5. Call & Gas Estimation -Read smart contracts without changing state - -- eth_call -- eth_estimateGas - -### 6. Transaction & Receipt Info -Get details about past transactions - -- eth_getTransactionByHash -- eth_getTransactionByBlockHashAndIndex -- eth_getTransactionByBlockNumberAndIndex -- eth_getTransactionReceipt - -### 7. Uncle Blocks (only relevant on old PoW chains) - -- eth_getUncleByBlockHashAndIndex -- eth_getUncleByBlockNumberAndIndex - -### 8. Logs / Events (Filter system) - -- eth_newFilter -- eth_newBlockFilter -- eth_newPendingTransactionFilter -- eth_uninstallFilter -- eth_getFilterChanges -- eth_getFilterLogs -- eth_getLogs - -## Quick Summary Table – Most Used Methods - -| Group | Very Common Methods | Less Common / Advanced | -|------------------------|--------------------------------------------------|-------------------------------------------------| -| Node info | eth_chainId, net_version, eth_syncing | web3_clientVersion, net_peerCount | -| Current state | eth_blockNumber, eth_getBalance, eth_getCode | eth_getStorageAt | -| Read contracts | eth_call, eth_estimateGas | — | -| Send transactions | eth_sendRawTransaction | eth_sendTransaction, eth_sign | -| Transaction lookup | eth_getTransactionReceipt, eth_getTransactionByHash | eth_getTransactionByBlock... | -| Logs / Events | eth_getLogs | eth_newFilter + eth_getFilterChanges | -| Blocks | eth_getBlockByNumber, eth_getBlockByHash | eth_getUncle... | - -## Useful Tips - -- Always use `"latest"`, `"pending"`, `"safe"`, or `"finalized"` as block tag when possible (safer than raw block numbers) -- `eth_call` and `eth_estimateGas` do **not** cost gas and do **not** change the blockchain -- `eth_sendRawTransaction` is the safest way to send already-signed transactions -- `eth_getLogs` is very powerful but can be slow on big ranges — use filters when you can - -Good starting point for most projects: - -```text -eth_chainId -eth_blockNumber -eth_getBalance -eth_call -eth_estimateGas -eth_sendRawTransaction -eth_getTransactionReceipt -eth_getLogs -``` \ No newline at end of file diff --git a/assignments/5-notes-on-terms/README.md b/assignments/5-notes-on-terms/README.md deleted file mode 100644 index 84f97a87..00000000 --- a/assignments/5-notes-on-terms/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Read, and write notes on: Exec hash, finalized root, epoch, block hash, slots, and fork choice - -## Block Hash - -**Block hash** in Ethereum is the cryptographic hash of the **block header**, which uniquely identifies each block and ensures the integrity of the blockchain. -It is generated using the **Keccak-256** hashing algorithm and includes all critical fields from the block header, such as: - -+ Parent block hash: This links the current block to its predecessor. -+ Timestamp: when the block was created. -+ Nonce: a value used in the proof-of-stake consensus process. -+ Difficulty level: indicates the complexity of mining the block (in PoW; now less relevant in PoS). -+ Merkle roots: hashes of the transaction tree, state tree, and receipt tree, summarizing the block's contents. - -Any change in the block header‐even a single bit‐results in a completely different block hash, making tampering detectable. This cryptographic linkage ensures the immutability of the Ethereum blockchain. - -The block hash is essential for verifying the authenticity and order of blocks across the network. It is also used in smart contracts via the blockhash opcode to reference the hash of a past block (up to 256 blocks back), enabling time-based logic and stateless validation. - -## Finalized root -**Finalized Root in Ethereum** refers to the **state root** of the most recent block that has been finalized by the consensus mechanism, specifically within Ethereum's Proof-of-Stake (PoS) system using the Casper FFG (Friendly Finality Gadget) protocol. - -The **finalized root** is **a cryptographic hash that represents the entire state of the Ethereum blockchain at a specific block, including all acoount balances, contract storage, and other state data. - -## Epoch -**Epoch in Ethereum** refers to a fixed time period in the Ethereum blockchain. Each epoch consists of **32 slots**, with each slot lasting **12 seconds**, resulting in an epoch duration of approximately **6.4 minutes**. - -In other words, 1 epoch is a bundle of 32 * 1 slot (12 seconds) = **6.4 minutes**. -2 - -Epoch is important to group/bundle slots together, give timeline to validator voting and give a timeline to finalization as it happens at each epoch's boundaries. - -## Slots -A **slot** however is an important unit of time in Ethereum's Proof-of-Stake (PoS) consensus mechanism, with each slot taking 12 seconds. - -It serves as a scheduled window during which a randomly selected validator is assigned to propose a block. -If the validator is online and functional, they create and broadcast a block; otherwise, the slot remains empty. - -## Fork choice -Fork Choice Rule is a core mechanism in Ethereum that enables nodes to agree on a single, canonical blockchain when the network experiences temporary splits or competing chains. -It acts as a decision-making protocol ensuring consensus across the decentralized network. - -In Ethereum's Proof of Stake (PoS) era, following the Merge on September 15, 2022, the **fork choice rule** is defined by the **combination of LMD GHOST (Latest Message Driven Greedy Heaviest Observed SubTree)** and **Casper FFG (Friendly Finality Gadget)**, collectively known as Gasper. -This system selects the chain head based on the heaviest sub-tree of validator attestations, where each validator's most recent vote counts toward a block's weight. - -+ **LMD GHOST** evaluates the chain with the greatest cumulative weight from recent validator attestations, promoting network alignment and resilience against attacks. -+ **Casper FFG** provides economic finality by finalizing checkpoints when a supermajority (≥2/3) of validator stake agrees, significantly reducing the risk of deep reorganizations. - -This evolution from the Longest Chain Rule (used in Proof of Work) to a validator-weighted, attestation-driven model improves security, finality speed, and energy efficiency. -The rule ensures that honest nodes converge on the same chain head, maintaining ledger consistency and enabling trust in DeFi, staking, and settlement systems. diff --git a/assignments/6-wallet-address/package-lock.json b/assignments/6-wallet-address/package-lock.json deleted file mode 100644 index 9cbca588..00000000 --- a/assignments/6-wallet-address/package-lock.json +++ /dev/null @@ -1,328 +0,0 @@ -{ - "name": "6-wallet-address", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "6-wallet-address", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "ethers": "^6.16.0" - }, - "devDependencies": { - "ts-node": "^10.9.2" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "license": "MIT" - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "license": "MIT" - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/ethers": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", - "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - } - } -} diff --git a/assignments/assign1/README.md b/assignments/assign1/README.md new file mode 100644 index 00000000..4f2ec78b --- /dev/null +++ b/assignments/assign1/README.md @@ -0,0 +1,32 @@ +My workspace +Etherscan/Transaction Hash) +Ethercan +is an Ethereum ledger, containing a bundled list of transactions and essential network. + +Observation +\*homepage:the homepage shows list of latest blocks and latest +transaction. +under the there is + +Transactions: it shows the time and total number of transactions processed on the Ethereum network +*Ether Price: +it displays the current price of ETH. +the blocks are arrange serially +observation on one of the (latest block) +after clicking the one of the block number +there is; +*block reward: which shows the transaction. +*burnt fee: token that is destroy. +*timestamp +*status:show the progress of the transaction. +*transaction: shows the number of transaction that is done in a block + +TRANSACTION HASH +**\* homepage overview** +transaction hash homepage is similar to Etherscan it has the +*timestamp. +*transaction status. +*gas fee +*transaction fee +*transaction value:which shows the amount of Eth transfer to the recipient. +*Address of recipient and beneficiary diff --git a/assignments/2-gas-hash/README.md b/assignments/assign2/README.md similarity index 100% rename from assignments/2-gas-hash/README.md rename to assignments/assign2/README.md diff --git a/assignments/assign2/calgas.js b/assignments/assign2/calgas.js new file mode 100644 index 00000000..b4471689 --- /dev/null +++ b/assignments/assign2/calgas.js @@ -0,0 +1,28 @@ +/** + * Calculate total gas fee. + * + @param {number} gasUsed - gas used (or gas limit for an estimate) + @param {number} baseFeePerGasGwei - base fee per gas in gwei + @param {number} priorityFeeGwei - tip per gas in gwei + @returns {{ totalFeeGwei: number, totalFeeEth: number, effectiveGasPriceGwei: number }} + */ +function calculateGasFee(gasUsed, baseFeePerGasGwei, priorityFeeGwei) { + const effectiveGasPriceGwei = baseFeePerGasGwei + priorityFeeGwei; + const totalFeeGwei = gasUsed * effectiveGasPriceGwei; + + // 1 ETH = 1e9 gwei + const totalFeeEth = totalFeeGwei / 1e9; + + return { + effectiveGasPriceGwei, + totalFeeGwei, + totalFeeEth, + }; +} + +const gasUsed = 21000; // simple transfer +const baseFeePerGasGwei = 10; // example current base fee +const priorityFeeGwei = 2; // your tip + +console.log(calculateGasFee(gasUsed, baseFeePerGasGwei, priorityFeeGwei)); +// -> { effectiveGasPriceGwei: 12, totalFeeGwei: 252000, totalFeeEth: 0.000252 } diff --git a/assignments/assign2/calgas.md b/assignments/assign2/calgas.md new file mode 100644 index 00000000..c866ae3c --- /dev/null +++ b/assignments/assign2/calgas.md @@ -0,0 +1,109 @@ +1. What gas actually is (first principles) + +Think of gas as a unit of computational work, not money. +Every operation a blockchain node performs (add, store, call, loop, etc.) has a fixed gas cost +This prevents infinite loops and spam +Gas measures how much work your transaction makes the network do +👉 Gas is work, not value. + +2. Why gas fees exist + Nodes (validators/miners) spend: + .CPU time + .Memory + .Disk (state storage) + .Network bandwidth + +Gas fees are how you pay for that work. +But work alone is not enough — we must also decide: +How much is each unit of work worth in money? +That leads to gas price. + +3. The three core variables + (A) GAS USED + +How much work your transaction actually performs. +Examples: +Simple ETH transfer → ~21,000 gas +Smart contract call → 50,000 – 500,000+ +Complex DeFi interaction → millions +This is determined by: +Sum of gas cost of each opcode executed + +(B) GAS LIMIT + +The maximum gas you are willing to allow. +Think of it as: +“I refuse to pay for more than this much work.” +Why it exists: +Protects you from buggy or malicious contracts +Stops infinite execution +If: +gas used ≤ gas limit → success +gas used > gas limit → transaction fails (but gas spent is lost) + +(C) GAS PRICE +How much money per unit of gas you’re willing to pay. +Measured in: +gwei (1 gwei = 10⁻⁹ ETH) +Higher gas price → faster inclusion in block. + +4.How the Components Are Derived + +The values in the formula are determined by a mix of network protocol rules and individual user choice: + + BASE FEE (Network-Derived): + +It is calculated algorithmically based on the size of the previous block. Each block has a target size (e.g., 15 million gas). If a block is more than 50% full, the base fee increases by up to 12.5% for the next block; if it is less than 50% full, the fee decreases. + + GAS LIMIT (Complexity-Derived): + +This is derived from the "weight" of the code being executed. Simple operations (like adding numbers) cost very little gas, while storing data on the blockchain is expensive. In 2026, developers are expanding the block gas limit toward 80 million units to handle higher transaction volumes. + + PRIORITY FEE (Market-Derived): + + +Users derive this value based on their personal urgency. During congestion, you may choose a higher tip to outbid other users for limited block spa + +5. Where this formula comes from (derivation) + Step-by-step reasoning + +Blockchain execution = computational work + +Each unit of work = 1 gas +Each gas must have a price (to compensate validators) + +Total cost = (number of work units) × (price per unit) +Thus: +Total Fee = Work × Price per Work + +Substituting: +Total Fee = Gas × Gas Price + +This is pure dimensional analysis: +Quantity Unit +Gas Used gas +Gas Price ETH / gas +Result ETH +Units cancel correctly → valid economic formula + +6. Why gas limit is not in the fee formula + + Gas limit is not a cost — it’s a constraint. + Actual cost depends on gas used, not gas limit. + However: + Maximum Possible Fee = Gas Limit × Gas Price + This is what your wallet shows before sending. + + 7.PRATICAL EXAMPLE (CURRENT 2026 STANDARDS) + +If you are sending ETH with the following parameters: + +Gas Units: 21,000 (standard) + +Base Fee: 50 Gwei + +Priority Fee: 2 Gwei + +Calculation: 21,000 × (50 + 2) = 1,092,000 Gwei + +Conversion: 1,092,000 Gwei ÷ 1,000,000,000 = 0.001092 ETH diff --git a/assignments/assign2/mkroot.js b/assignments/assign2/mkroot.js new file mode 100644 index 00000000..bd6daa7f --- /dev/null +++ b/assignments/assign2/mkroot.js @@ -0,0 +1,213 @@ +import { sha256, keccak256, randomBytes, toUtf8Bytes, concat } from 'ethers'; + +/** + * Generates a list of random hashes using SHA-256 or Keccak-256 + * @param {number} count - Number of hashes to generate + * @param {string} algorithm - Hash algorithm: 'sha256' or 'keccak256' + * @returns {Object} Object containing hashes array and algorithm used + */ +function generateRandomHashes(count, algorithm = 'keccak256') { + const hashes = []; + + for (let i = 0; i < count; i++) { + const randomData = randomBytes(32); + + let hash; + if (algorithm === 'sha256') { + hash = sha256(randomData); + } else if (algorithm === 'keccak256') { + hash = keccak256(randomData); + } else { + throw new Error('Unsupported algorithm. Use "sha256" or "keccak256"'); + } + + hashes.push(hash); + } + + return { + hashes, + algorithm, + }; +} + +/** + * Hash a string using the specified algorithm + * @param {string} text - Text to hash + * @param {string} algorithm - Hash algorithm: 'sha256' or 'keccak256' + * @returns {Object} Object containing hash and algorithm used + */ +function hashString(text, algorithm = 'keccak256') { + const bytes = toUtf8Bytes(text); + + let hash; + if (algorithm === 'sha256') { + hash = sha256(bytes); + } else if (algorithm === 'keccak256') { + hash = keccak256(bytes); + } else { + throw new Error('Unsupported algorithm. Use "sha256" or "keccak256"'); + } + + return { + hash, + algorithm, + }; +} + +/** + * Combines two hashes by sorting them and hashing the concatenation + * @param {string} left - Left hash + * @param {string} right - Right hash + * @param {string} algorithm - Hash algorithm to use (internal) + * @returns {string} Combined hash + */ +function combineHashes(left, right, algorithm) { + // Sort hashes to ensure consistent ordering + const [first, second] = left < right ? [left, right] : [right, left]; + + console.log( + ` Combining: ${first.slice(0, 10)}... + ${second.slice(0, 10)}...` + ); + + // Concatenate and hash + const combined = concat([first, second]); + const hash = algorithm === 'sha256' ? sha256(combined) : keccak256(combined); + + console.log(` Result: ${hash.slice(0, 10)}...`); + + return hash; +} + +/** + * Builds a Merkle root from the result of generateRandomHashes or an array with algorithm + * @param {Object|string[]} leavesInput - Either result from generateRandomHashes or array of hashes + * @param {string} [algorithmOverride] - Optional algorithm override (only if leavesInput is plain array) + * @returns {string} Merkle root hash + */ +function buildMerkleRoot(leavesInput, algorithmOverride) { + let leaves, algorithm; + + // Check if input is from generateRandomHashes (has algorithm property) + if ( + leavesInput && + typeof leavesInput === 'object' && + leavesInput.hashes && + leavesInput.algorithm + ) { + leaves = leavesInput.hashes; + algorithm = leavesInput.algorithm; + } else if (Array.isArray(leavesInput)) { + // Plain array provided + leaves = leavesInput; + algorithm = algorithmOverride || 'keccak256'; + } else { + throw new Error( + 'Invalid input. Provide result from generateRandomHashes or array of hashes.' + ); + } + + if (!leaves || leaves.length === 0) { + throw new Error('Cannot build Merkle tree from empty array'); + } + + console.log('\n========================================'); + console.log('BUILDING MERKLE TREE'); + console.log('========================================'); + console.log(`Algorithm: ${algorithm.toUpperCase()}`); + console.log(`Total leaves: ${leaves.length}`); + console.log('========================================\n'); + + // Log initial leaves + console.log('LEVEL 0 (Leaves):'); + leaves.forEach((leaf, i) => { + console.log(` [${i}] ${leaf}`); + }); + console.log(''); + + let currentLevel = [...leaves]; + let levelNumber = 1; + + // Build tree level by level + while (currentLevel.length > 1) { + console.log(`LEVEL ${levelNumber}:`); + console.log( + ` Processing ${currentLevel.length} nodes -> ${Math.ceil( + currentLevel.length / 2 + )} parent nodes` + ); + console.log(''); + + const nextLevel = []; + + // Process pairs + for (let i = 0; i < currentLevel.length; i += 2) { + if (i + 1 < currentLevel.length) { + // We have a pair + console.log(` Pair ${Math.floor(i / 2)}:`); + console.log(` Left: ${currentLevel[i]}`); + console.log(` Right: ${currentLevel[i + 1]}`); + + const parentHash = combineHashes( + currentLevel[i], + currentLevel[i + 1], + algorithm + ); + nextLevel.push(parentHash); + + console.log(''); + } else { + // Odd one out - promote to next level + console.log(` Single node (promoted):`); + console.log(` ${currentLevel[i]}`); + nextLevel.push(currentLevel[i]); + console.log(''); + } + } + + // Log the resulting level + console.log(` Level ${levelNumber} Result:`); + nextLevel.forEach((hash, i) => { + console.log(` [${i}] ${hash}`); + }); + console.log('\n' + '----------------------------------------\n'); + + currentLevel = nextLevel; + levelNumber++; + } + + const root = currentLevel[0]; + + console.log('========================================'); + console.log('MERKLE ROOT (Final):'); + console.log(root); + console.log('========================================\n'); + + return root; +} + +// Example usage - Algorithm specified ONLY at generation time +console.log('Generating 7 hashes for Merkle tree...\n'); + +// The ONLY place we specify the algorithm +const result = generateRandomHashes(75, 'sha256'); // Change to 'sha256' if needed + +console.log(`Using ${result.algorithm.toUpperCase()} for entire process\n`); +console.log('Generated leaves:'); +result.hashes.forEach((hash, i) => { + console.log(`${i + 1}. ${hash}`); +}); + +// Algorithm is implicitly carried through - no need to specify again! +const merkleRoot = buildMerkleRoot(result); + +console.log('\n========================================'); +console.log('SUMMARY'); +console.log('========================================'); +console.log(`Hash Algorithm: ${result.algorithm.toUpperCase()}`); +console.log(`Total leaves: ${result.hashes.length}`); +console.log(`Tree height: ${Math.ceil(Math.log2(result.hashes.length)) + 1}`); +console.log(`Merkle Root: ${merkleRoot}`); +console.log('========================================'); + +// Export functions +export { generateRandomHashes, hashString, buildMerkleRoot, combineHashes }; diff --git a/assignments/assign2/package.json b/assignments/assign2/package.json new file mode 100644 index 00000000..5aa80761 --- /dev/null +++ b/assignments/assign2/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "ethers": "^6.16.0" + }, + "type": "module" +} diff --git a/assignments/assign3/ETHSUM.md b/assignments/assign3/ETHSUM.md new file mode 100644 index 00000000..3b2056f2 --- /dev/null +++ b/assignments/assign3/ETHSUM.md @@ -0,0 +1,91 @@ +ETHEREUM BOOK CHAPT.1 +Overview. + +From a computer science perspective, Ethereum is a deterministic but practically unbounded state machine, consisting of a globally accessible singleton state and a virtual machine that applies changes to that state. in a simple term Ethereum is a decentralized, open-source blockchain platform that enables developers to build and deploy smart contracts and decentralized applications. + +COMPONENT OF BLOCKCHAIN +Permissionless: + +Permissionless blockchains, like Bitcoin and Ethereum, are accessible to anyone. These decentralized networks allow anyone to join, participate in the consensus process, and read and write data, promoting trust through transparency. + +Permissioned: + +Permissioned blockchains restrict access, allowing only authorized participants to join the network and perform certain actions. + +Public: + +Public blockchains are decentralized and open to everyone, allowing broad participation in network activities and ensuring transparency through widespread distribution and consensus mechanisms. + +Private: + +Private blockchains limit access to a specific group of participants, often within organizations or among trusted partners. + +_ETHEREUM STAGES of DEVELOPMENT_ +The four main development stages are codenamed Frontier, Homestead, Metropolis, and Serenity.The Serenity stage has been further broken down into six substages codenamed The Merge, The Surge, The Scourge, The Verge, The Purge, and The Splurge. + +\*FRONTIER: Frontier prepared the foundation for miners and developers by enabling the setup of mining rigs, the initiation of ETH token trading, and the testing of decentralized applications (DApps) in a minimal network setting + +\*HOMESTEADS:Homestead made Ethereum safer and more stable through key protocol updates (EIP-2, EIP-7, and EIP-8).These upgrades enhanced developer friendliness and paved the way for further protocol improvements. + +\*METROPOLIS: Metropolis aimed to increase network functionality, fostering DApp creation and overall network utility. + +\*SERENITY:Serenity focuses on making Ethereum more sustainable and capable of handling a growing number of users and applications. This stage addresses critical issues like high energy consumption and network congestion, clearing the way for a more robust and efficient blockchain.The Serenity is divided into several substages, each addressing specific aspects of the network’s evolution.the five Serenity substages are being developed at the same time + +1.The merge: The Merge combines Ethereum’s mainnet with the Beacon Chain (The Beacon Chain is the backbone of Ethereum's proof-of-stake consensus system,The Beacon Chain manages the validator registry, implements the consensus rules, and distributes rewards and penalties.)it officially transitioning the network to PoS and reducing energy consumption significantly. + +2.The Surge: +The Surge introduces sharding, increasing Ethereum’s scalability by splitting the network into smaller, manageable pieces, which allows for more transactions per second. + +3.The Purge: +The Purge aims to reduce the historical data stored on Ethereum,simplifying node operation and lowering network congestion. + +The Splurge:The Splurge includes various minor upgrades and optimizations to ensure that Ethereum runs smoothly and efficiently after all major changes are implemented. + +ETHEREUM COMPONENT + +\*P2P network: +Ethereum runs on the Ethereum main network, which is addressable on TCP port 30303, and runs a protocol called ÐΞVp2p. + +\*Consensus rules: +Ethereum’s original consensus protocol was Ethash, a PoW model defined in the reference specification: the “Yellow Paper.” It then evolved to PoS in September 2022 during The Merge upgrade (see Chapter 15). + +\*Transactions: +Ethereum transactions are network messages that include (among other things) a sender, a recipient, a value, and a data payload. + +\*State machine: +Ethereum state transitions are processed by the Ethereum Virtual Machine (EVM), a stack-based virtual machine that executes bytecode (machine-language instructions). EVM programs called smart contracts are written in high-level languages (e.g., Solidity) and compiled to bytecode for execution on the EVM. + +\*Data structures: +Ethereum’s state is stored locally on each node as a database (usually Google’s LevelDB), which contains the transactions and system state in a serialized hashed data structure called a Merkle-Patricia trie. + +\*Consensus algorithm: +Ethereum transitioned from a PoW to a PoS consensus mechanism to enhance energy efficiency and scalability. In PoS, validators stake their cryptocurrency to earn the right to validate transactions, create new blocks, and maintain network security. Ethereum’s PoS is the fusion of two distinct algorithms: Casper the Friendly Finality Gadget (FFG) and GHOST (Greedy Heaviest Observed Subtree) with latest message driven (LMD) updates (more on this in Chapter 15). + +\*Economic security: +Ethereum uses a PoS algorithm called Gasper that provides economic security to the blockchain. We’ll explore how Gasper works in detail in Chapter 15, including its role in finality and validator coordination. + +\*Clients: +Ethereum has several interoperable implementations of its execution and consensus client software, the most prominent of which are go-ethereum (Geth) and Nethermind for execution and Prysm and Lighthouse for consensus. + +WHY WE LEARN ETHEREUM +Ethereum is a great platform for learning about blockchains, ethereum combine multiple disciplines into one domain: programming, information security, cryptography, economics, distributed systems, P2P networks, and so on. Ethereum makes this learning curve a lot less steep, so you can get started quickly. But just below the surface of a deceptively simple environment lies a lot more. As you learn and start looking deeper, there’s always another layer of complexity and wonder. + +CHAPTER (six) +Overview. + +Transactions are signed messages originated by an externally owned account, transmitted by the Ethereum network, and recorded on the Ethereum blockchain + +TRANSACTION TYPES + +\*Legacy type:A legacy transaction is a serialized binary message,basically it convert data from its original structure like objects, arrays, or complex data typesinto a compact binary format for storage or transmission. + +\*EIP-2930 Transactions:these type of transaction are equal to the previous transaction type, but with a new field called (access list). It's an array of (addresses, storage slots) that lets a user prepay for addresses and storage slots that are going to be touched by the transaction. + +\*EIP-1559 Transactions:They completely change the structure of the fee market on Ethereum by introducing a new protocol parameter: the base fee.The base fee represents the minimum fee you need to pay to send a transaction on the Ethereum network. + +\*EIP-4844 Transactions: They are also called blob-carrying transactions because they come with a sidecar—a blob—which contains a large amount of data. + +\*EIP-7702 Transactions:They allow EOAs(Externally Owned Account)to set the code in their account. Traditionally, EOAs have an empty code; they can just start a transaction but cannot really perform complex operations, unless they are interacting with a smart contract. EIP-7702 changes this, making it possible for EOAs to do operations such as the following. + +TRANSACTION NONCE +Is a counter that tracks the number of transactions sent from an account (specifically an EOA - Externally Owned Account). diff --git a/assignments/assign3/blockHash.js b/assignments/assign3/blockHash.js new file mode 100644 index 00000000..3a12314c --- /dev/null +++ b/assignments/assign3/blockHash.js @@ -0,0 +1,23 @@ +const crypto = require("crypto"); + +function deriveBlockHash(block) { + const blockString = JSON.stringify({ + nonce: block.nonce || 0, + index: block.index, + timestamp: block.timestamp, + data: block.data, + previousHash: block.previousHash, + }); + + return crypto.createHash("sha256").update(blockString).digest("hex"); +} +const block = { + nonce: 1, + index: 1, + timestamp: Date.now(), + data: "niffy", + previousHash: "123456789", +}; + +const hash = deriveBlockHash(block); +console.log("Block Hash:", hash); \ No newline at end of file diff --git a/assignments/assign4/README.md b/assignments/assign4/README.md new file mode 100644 index 00000000..3952c0e1 --- /dev/null +++ b/assignments/assign4/README.md @@ -0,0 +1,22 @@ +WHAT is AN RPC? An RPC stands for (Remote Procedure Call)a protocol that allows a program to execute a function or procedure on another computer/server as if it were a local function call. + +JSON RPC ON THE BLOCKCHAIN JSON-RPC is used as the communication protocol between a client and a blockchain node. It allows to query blockchain data (like account balances, transaction history,or block info) and send transactions to the network.the JSON-RPC methods vary by blockchain, and also the methods are divided into (two) (A)read operations and (B) write operations + +\*\*KEY DIFFRENCES + +aspect read methods write method +cost free requirs gas(Eth) +speed instant wait for block confirmation +stage change no yes +signing not required must be signed +. COMMON PATTERN OF JSON-RPC ACROSS MAJOR BLOCKCHAIN + +Common Patterns Across Blockchains: + +category bitcoin ethereum solana +Block height getblockcount eth_blockNumber getBlockHeight +Balance getbalance eth_getBalance getBalance +Send TX sendrawtransaction eth_sendRawTransaction sendTransaction +block data getblock eth_getBlockByNumber getBlock +TX details gettransaction eth_getTransactionByHash getTransaction +In summary: JSON-RPC is how applications talk to blockchain nodes programmatically. diff --git a/assignments/assign5/README.md b/assignments/assign5/README.md new file mode 100644 index 00000000..8725ebd3 --- /dev/null +++ b/assignments/assign5/README.md @@ -0,0 +1,55 @@ +EXECUTION HASH +or the execution block hash, is a cryptographic hash that represent the execution layer block in enthereum post merge architecture. + +- How the Execution Hash Works + The consensus client (like Prysm, Lighthouse, Teku, Nimbus, or Lodestar) receives execution payloads from the execution client (like Geth, Besu, Nethermind, or Erigon)The execution hash serves as a commitment to that payload's contents. + purpose + -It ensures the consensus layer and execution layer agree on the same block data + -Security: Ensures validators can't propose different execution payloads to different peers + -Integrity: Provides cryptographic proof that the block hasn't been tampered with + +- What the finalized root means: + The "finalized root" refers to a checkpoint (typically an epoch boundary block) that has been finalized by the consensus mechanism + Once finalized, this block and all blocks before it are considered permanent and irreversible + Finality typically occurs after two epochs (about 12.8 minutes under normal conditions) + +\*Why it matters: + +-Finalized blocks provide economic certainty - they cannot be reverted without destroying a significant portion of staked ETH +-This is part of Casper FFG (Friendly Finality Gadget), which provides stronger guarantees than probabilistic finality +-Applications and exchanges can treat finalized transactions as truly settled + +\*In your consensus client: + +When your consensus client shows a finalized root, it means: +-Your node recognizes which checkpoint the network has agreed is permanent +-Transactions in finalized blocks have maximum security. + +\*fork choice: +refers to the algorithm that determines which block is the "best" head of the chain + +- EPOCH: + +A unit of time in the Beacon Chain, consisting of 32 slots (approximately 6.4 minutes). + +It is the primary cycle for administrative tasks, including validator committee assignments, justifying and finalizing checkpoints, and managing validator balances. + +- Block Hash (Beacon Block Root): + +The cryptographic hash (often referred to as the state_root or block_root) of the entire Beacon Chain block header. + +This includes the consensus data (attestations, sync committee signatures, etc.) and a reference to the execution payload hash (exec_hash). + +- Slot: + +A discrete, 12-second interval of time during which a single validator is randomly chosen to propose a new Beacon Chain block. +The fundamental unit of block production time. + +- Fork Choice (LMD-GHOST): + The algorithm (Latest Message-Driven Greediest Heaviest Observed SubTree) that the network uses to determine the canonical, "correct" chain head. + It works by having validators attest to the "head" block they see. The algorithm then selects the chain with the greatest accumulated weight of attestations (the "heaviest" subtree). + +How They Work Together +The chain progresses in slots. In each slot, a proposer creates a Beacon Block (with its Block Hash) that includes an Exec Hash. +Every 32 slots (one epoch), the attestations are tallied. When two consecutive epochs are justified, the first one's checkpoint block becomes finalized (Finalized Root). +At all times, nodes use the Fork Choice rule to identify the current valid chain head, which is built upon the latest, attested blocks, ultimately anchored by the latest Finalized Root. diff --git a/assignments/6-wallet-address/README.md b/assignments/assign6/README.md similarity index 100% rename from assignments/6-wallet-address/README.md rename to assignments/assign6/README.md diff --git a/assignments/6-wallet-address/dictionary.json b/assignments/assign6/dictionary.json similarity index 100% rename from assignments/6-wallet-address/dictionary.json rename to assignments/assign6/dictionary.json diff --git a/assignments/6-wallet-address/package.json b/assignments/assign6/package.json similarity index 100% rename from assignments/6-wallet-address/package.json rename to assignments/assign6/package.json diff --git a/assignments/6-wallet-address/tsconfig.json b/assignments/assign6/tsconfig.json similarity index 100% rename from assignments/6-wallet-address/tsconfig.json rename to assignments/assign6/tsconfig.json diff --git a/assignments/6-wallet-address/wallet-address.ts b/assignments/assign6/wallet-address.js similarity index 99% rename from assignments/6-wallet-address/wallet-address.ts rename to assignments/assign6/wallet-address.js index 08f09656..66bd469d 100644 --- a/assignments/6-wallet-address/wallet-address.ts +++ b/assignments/assign6/wallet-address.js @@ -1,4 +1,3 @@ - import fs from 'node:fs'; import { randomBytes, createHash } from 'node:crypto'; import { keccak256, SigningKey } from 'ethers'; From bf3526ca6af9ecbe502c188a40b45e1792fa3985 Mon Sep 17 00:00:00 2001 From: JEREMIAH PETER Date: Sun, 15 Feb 2026 02:54:14 +0100 Subject: [PATCH 2/4] feat:A todolist --- assignments/assign7todo/contracts/Todo.sol | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 assignments/assign7todo/contracts/Todo.sol diff --git a/assignments/assign7todo/contracts/Todo.sol b/assignments/assign7todo/contracts/Todo.sol new file mode 100644 index 00000000..290999e0 --- /dev/null +++ b/assignments/assign7todo/contracts/Todo.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +contract Todo{ + uint256 todoCounter; + + enum Status{ + Pending, + Done, + Cancelled, + Defaulted + } + + struct TodoList{ + uint id; + address owner; + string text; + Status status; + uint256 deadline; + } + + mapping(uint => TodoList) todos; + + event TodoCreated(string text, uint deadline); + + + +function createTodo(string memory _text, uint _deadline) external returns(uint){ + require(bytes(_text).length > 0, "Empty text"); + require(_deadline > (block.timestamp + 600), "Invalid deadline"); + require(msg.sender != address(0), "Zero address"); + + todoCounter++; + + //creating a new todo and save it + todos[todoCounter] = TodoList(todoCounter, msg.sender, _text, Status.Pending, _deadline); + + emit TodoCreated(_text, _deadline); + return todoCounter; +} + +function markAsDone(uint _id) external { + require((_id > 0) && (_id <= todoCounter) , 'invalid id'); + TodoList storage todo = todos[_id]; + require(todo.status == Status.Pending, "Not pending"); + require(msg.sender == todo.owner, "unauthorized Caller"); + + if(block.timestamp > todo.deadline){ + todo.status = Status.Defaulted; + } + else{ + todo.status = Status.Done; + } + +} + +} \ No newline at end of file From 9ad96e427fe15575a3d596715bdcd941ef926eea Mon Sep 17 00:00:00 2001 From: JEREMIAH PETER Date: Mon, 16 Feb 2026 18:33:02 +0100 Subject: [PATCH 3/4] feat: submitting assignment 7 - todo --- assignments/assign7todo/.gitignore | 20 ++++++ assignments/assign7todo/README.md | 57 +++++++++++++++ assignments/assign7todo/contracts/Counter.sol | 19 +++++ .../assign7todo/contracts/Counter.t.sol | 32 +++++++++ assignments/assign7todo/contracts/Todo.sol | 2 +- assignments/assign7todo/hardhat.config.ts | 44 ++++++++++++ .../artifacts/TodoModule#Todo.json | 70 +++++++++++++++++++ ...8893556a201a54858b5d523ac1037fb68d670.json | 39 +++++++++++ .../chain-11155111/deployed_addresses.json | 3 + .../deployments/chain-11155111/journal.jsonl | 8 +++ .../assign7todo/ignition/modules/Todo.ts | 10 +++ assignments/assign7todo/package.json | 23 ++++++ assignments/assign7todo/scripts/send-op-tx.ts | 22 ++++++ assignments/assign7todo/test/Counter.ts | 36 ++++++++++ assignments/assign7todo/tsconfig.json | 13 ++++ 15 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 assignments/assign7todo/.gitignore create mode 100644 assignments/assign7todo/README.md create mode 100644 assignments/assign7todo/contracts/Counter.sol create mode 100644 assignments/assign7todo/contracts/Counter.t.sol create mode 100644 assignments/assign7todo/hardhat.config.ts create mode 100644 assignments/assign7todo/ignition/deployments/chain-11155111/artifacts/TodoModule#Todo.json create mode 100644 assignments/assign7todo/ignition/deployments/chain-11155111/build-info/solc-0_8_28-0a18893556a201a54858b5d523ac1037fb68d670.json create mode 100644 assignments/assign7todo/ignition/deployments/chain-11155111/deployed_addresses.json create mode 100644 assignments/assign7todo/ignition/deployments/chain-11155111/journal.jsonl create mode 100644 assignments/assign7todo/ignition/modules/Todo.ts create mode 100644 assignments/assign7todo/package.json create mode 100644 assignments/assign7todo/scripts/send-op-tx.ts create mode 100644 assignments/assign7todo/test/Counter.ts create mode 100644 assignments/assign7todo/tsconfig.json diff --git a/assignments/assign7todo/.gitignore b/assignments/assign7todo/.gitignore new file mode 100644 index 00000000..991a319e --- /dev/null +++ b/assignments/assign7todo/.gitignore @@ -0,0 +1,20 @@ +# Node modules +/node_modules + +# Compilation output +/dist + +# pnpm deploy output +/bundle + +# Hardhat Build Artifacts +/artifacts + +# Hardhat compilation (v2) support directory +/cache + +# Typechain output +/types + +# Hardhat coverage reports +/coverage diff --git a/assignments/assign7todo/README.md b/assignments/assign7todo/README.md new file mode 100644 index 00000000..968246e9 --- /dev/null +++ b/assignments/assign7todo/README.md @@ -0,0 +1,57 @@ +# Sample Hardhat 3 Beta Project (`mocha` and `ethers`) + +This project showcases a Hardhat 3 Beta project using `mocha` for tests and the `ethers` library for Ethereum interactions. + +To learn more about the Hardhat 3 Beta, please visit the [Getting Started guide](https://hardhat.org/docs/getting-started#getting-started-with-hardhat-3). To share your feedback, join our [Hardhat 3 Beta](https://hardhat.org/hardhat3-beta-telegram-group) Telegram group or [open an issue](https://github.com/NomicFoundation/hardhat/issues/new) in our GitHub issue tracker. + +## Project Overview + +This example project includes: + +- A simple Hardhat configuration file. +- Foundry-compatible Solidity unit tests. +- TypeScript integration tests using `mocha` and ethers.js +- Examples demonstrating how to connect to different types of networks, including locally simulating OP mainnet. + +## Usage + +### Running Tests + +To run all the tests in the project, execute the following command: + +```shell +npx hardhat test +``` + +You can also selectively run the Solidity or `mocha` tests: + +```shell +npx hardhat test solidity +npx hardhat test mocha +``` + +### Make a deployment to Sepolia + +This project includes an example Ignition module to deploy the contract. You can deploy this module to a locally simulated chain or to Sepolia. + +To run the deployment to a local chain: + +```shell +npx hardhat ignition deploy ignition/modules/Counter.ts +``` + +To run the deployment to Sepolia, you need an account with funds to send the transaction. The provided Hardhat configuration includes a Configuration Variable called `SEPOLIA_PRIVATE_KEY`, which you can use to set the private key of the account you want to use. + +You can set the `SEPOLIA_PRIVATE_KEY` variable using the `hardhat-keystore` plugin or by setting it as an environment variable. + +To set the `SEPOLIA_PRIVATE_KEY` config variable using `hardhat-keystore`: + +```shell +npx hardhat keystore set SEPOLIA_PRIVATE_KEY +``` + +After setting the variable, you can run the deployment with the Sepolia network: + +```shell +npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts +``` diff --git a/assignments/assign7todo/contracts/Counter.sol b/assignments/assign7todo/contracts/Counter.sol new file mode 100644 index 00000000..8d00cb7c --- /dev/null +++ b/assignments/assign7todo/contracts/Counter.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +contract Counter { + uint public x; + + event Increment(uint by); + + function inc() public { + x++; + emit Increment(1); + } + + function incBy(uint by) public { + require(by > 0, "incBy: increment should be positive"); + x += by; + emit Increment(by); + } +} diff --git a/assignments/assign7todo/contracts/Counter.t.sol b/assignments/assign7todo/contracts/Counter.t.sol new file mode 100644 index 00000000..ac71d5b8 --- /dev/null +++ b/assignments/assign7todo/contracts/Counter.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import {Counter} from "./Counter.sol"; +import {Test} from "forge-std/Test.sol"; + +// Solidity tests are compatible with foundry, so they +// use the same syntax and offer the same functionality. + +contract CounterTest is Test { + Counter counter; + + function setUp() public { + counter = new Counter(); + } + + function test_InitialValue() public view { + require(counter.x() == 0, "Initial value should be 0"); + } + + function testFuzz_Inc(uint8 x) public { + for (uint8 i = 0; i < x; i++) { + counter.inc(); + } + require(counter.x() == x, "Value after calling inc x times should be x"); + } + + function test_IncByZero() public { + vm.expectRevert(); + counter.incBy(0); + } +} diff --git a/assignments/assign7todo/contracts/Todo.sol b/assignments/assign7todo/contracts/Todo.sol index 290999e0..d7ff8656 100644 --- a/assignments/assign7todo/contracts/Todo.sol +++ b/assignments/assign7todo/contracts/Todo.sol @@ -54,4 +54,4 @@ function markAsDone(uint _id) external { } -} \ No newline at end of file +} \ No newline at end of file diff --git a/assignments/assign7todo/hardhat.config.ts b/assignments/assign7todo/hardhat.config.ts new file mode 100644 index 00000000..1b645c9b --- /dev/null +++ b/assignments/assign7todo/hardhat.config.ts @@ -0,0 +1,44 @@ +import "dotenv/config"; +import hardhatToolboxMochaEthersPlugin from "@nomicfoundation/hardhat-toolbox-mocha-ethers"; +import { configVariable, defineConfig } from "hardhat/config"; + +export default defineConfig({ + plugins: [hardhatToolboxMochaEthersPlugin], + solidity: { + profiles: { + default: { + version: "0.8.28", + }, + production: { + version: "0.8.28", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + }, + }, + networks: { + hardhatMainnet: { + type: "edr-simulated", + chainType: "l1", + }, + hardhatOp: { + type: "edr-simulated", + chainType: "op", + }, + sepolia: { + type: "http", + chainType: "l1", + url: configVariable("SEPOLIA_RPC_URL"), + accounts: [configVariable("SEPOLIA_PRIVATE_KEY")], + }, + }, + verify: { + etherscan: { + apiKey: configVariable("ETHERSCAN_API_KEY"), + }, + }, +}); diff --git a/assignments/assign7todo/ignition/deployments/chain-11155111/artifacts/TodoModule#Todo.json b/assignments/assign7todo/ignition/deployments/chain-11155111/artifacts/TodoModule#Todo.json new file mode 100644 index 00000000..6c8c14a7 --- /dev/null +++ b/assignments/assign7todo/ignition/deployments/chain-11155111/artifacts/TodoModule#Todo.json @@ -0,0 +1,70 @@ +{ + "_format": "hh3-artifact-1", + "contractName": "Todo", + "sourceName": "contracts/Todo.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "text", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "TodoCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_text", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_deadline", + "type": "uint256" + } + ], + "name": "createTodo", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + } + ], + "name": "markAsDone", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b506106568061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063d74de14d14610038578063ece28c6c1461004d575b5f5ffd5b61004b610046366004610372565b610072565b005b61006061005b36600461039d565b6101a4565b60405190815260200160405180910390f35b5f8111801561008257505f548111155b6100c05760405162461bcd60e51b815260206004820152600a6024820152691a5b9d985b1a59081a5960b21b60448201526064015b60405180910390fd5b5f8181526001602052604081209060038083015460ff16908111156100e7576100e7610452565b146101225760405162461bcd60e51b815260206004820152600b60248201526a4e6f742070656e64696e6760a81b60448201526064016100b7565b60018101546001600160a01b031633146101745760405162461bcd60e51b81526020600482015260136024820152723ab730baba3437b934bd32b21021b0b63632b960691b60448201526064016100b7565b8060040154421115610193576003908101805460ff1916909117905550565b600301805460ff1916600117905550565b5f5f8351116101e25760405162461bcd60e51b815260206004820152600a602482015269115b5c1d1e481d195e1d60b21b60448201526064016100b7565b6101ee4261025861047a565b821161022f5760405162461bcd60e51b815260206004820152601060248201526f496e76616c696420646561646c696e6560801b60448201526064016100b7565b3361026b5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b60448201526064016100b7565b5f805490806102798361048d565b90915550506040805160a0810182525f80548252336020830152918101859052906060820190815260209081018490525f805481526001808352604091829020845181559284015190830180546001600160a01b0319166001600160a01b0390921691909117905582015160028201906102f39082610529565b506060820151816003015f6101000a81548160ff0219169083600381111561031d5761031d610452565b0217905550608082015181600401559050507f022c3fffe570decf2328dbf4f2af598df5112da7e31568af8b927c48276ccae383836040516103609291906105e4565b60405180910390a1505f545b92915050565b5f60208284031215610382575f5ffd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156103ae575f5ffd5b823567ffffffffffffffff8111156103c4575f5ffd5b8301601f810185136103d4575f5ffd5b803567ffffffffffffffff8111156103ee576103ee610389565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561041d5761041d610389565b604052818152828201602001871015610434575f5ffd5b816020840160208301375f6020928201830152969401359450505050565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8082018082111561036c5761036c610466565b5f6001820161049e5761049e610466565b5060010190565b600181811c908216806104b957607f821691505b6020821081036104d757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561052457805f5260205f20601f840160051c810160208510156105025750805b601f840160051c820191505b81811015610521575f815560010161050e565b50505b505050565b815167ffffffffffffffff81111561054357610543610389565b6105578161055184546104a5565b846104dd565b6020601f821160018114610589575f83156105725750848201515b5f19600385901b1c1916600184901b178455610521565b5f84815260208120601f198516915b828110156105b85787850151825560209485019460019092019101610598565b50848210156105d557868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b604081525f83518060408401528060208601606085015e5f606082850101526060601f19601f830116840101915050826020830152939250505056fea2646970667358221220422aab76da81c357c07497ea804246ba9bc2ff7312712e4fc2334e7254ba51da64736f6c634300081c0033", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063d74de14d14610038578063ece28c6c1461004d575b5f5ffd5b61004b610046366004610372565b610072565b005b61006061005b36600461039d565b6101a4565b60405190815260200160405180910390f35b5f8111801561008257505f548111155b6100c05760405162461bcd60e51b815260206004820152600a6024820152691a5b9d985b1a59081a5960b21b60448201526064015b60405180910390fd5b5f8181526001602052604081209060038083015460ff16908111156100e7576100e7610452565b146101225760405162461bcd60e51b815260206004820152600b60248201526a4e6f742070656e64696e6760a81b60448201526064016100b7565b60018101546001600160a01b031633146101745760405162461bcd60e51b81526020600482015260136024820152723ab730baba3437b934bd32b21021b0b63632b960691b60448201526064016100b7565b8060040154421115610193576003908101805460ff1916909117905550565b600301805460ff1916600117905550565b5f5f8351116101e25760405162461bcd60e51b815260206004820152600a602482015269115b5c1d1e481d195e1d60b21b60448201526064016100b7565b6101ee4261025861047a565b821161022f5760405162461bcd60e51b815260206004820152601060248201526f496e76616c696420646561646c696e6560801b60448201526064016100b7565b3361026b5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b60448201526064016100b7565b5f805490806102798361048d565b90915550506040805160a0810182525f80548252336020830152918101859052906060820190815260209081018490525f805481526001808352604091829020845181559284015190830180546001600160a01b0319166001600160a01b0390921691909117905582015160028201906102f39082610529565b506060820151816003015f6101000a81548160ff0219169083600381111561031d5761031d610452565b0217905550608082015181600401559050507f022c3fffe570decf2328dbf4f2af598df5112da7e31568af8b927c48276ccae383836040516103609291906105e4565b60405180910390a1505f545b92915050565b5f60208284031215610382575f5ffd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156103ae575f5ffd5b823567ffffffffffffffff8111156103c4575f5ffd5b8301601f810185136103d4575f5ffd5b803567ffffffffffffffff8111156103ee576103ee610389565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561041d5761041d610389565b604052818152828201602001871015610434575f5ffd5b816020840160208301375f6020928201830152969401359450505050565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8082018082111561036c5761036c610466565b5f6001820161049e5761049e610466565b5060010190565b600181811c908216806104b957607f821691505b6020821081036104d757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561052457805f5260205f20601f840160051c810160208510156105025750805b601f840160051c820191505b81811015610521575f815560010161050e565b50505b505050565b815167ffffffffffffffff81111561054357610543610389565b6105578161055184546104a5565b846104dd565b6020601f821160018114610589575f83156105725750848201515b5f19600385901b1c1916600184901b178455610521565b5f84815260208120601f198516915b828110156105b85787850151825560209485019460019092019101610598565b50848210156105d557868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b604081525f83518060408401528060208601606085015e5f606082850101526060601f19601f830116840101915050826020830152939250505056fea2646970667358221220422aab76da81c357c07497ea804246ba9bc2ff7312712e4fc2334e7254ba51da64736f6c634300081c0033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "immutableReferences": {}, + "inputSourceName": "project/contracts/Todo.sol", + "buildInfoId": "solc-0_8_28-0a18893556a201a54858b5d523ac1037fb68d670" +} \ No newline at end of file diff --git a/assignments/assign7todo/ignition/deployments/chain-11155111/build-info/solc-0_8_28-0a18893556a201a54858b5d523ac1037fb68d670.json b/assignments/assign7todo/ignition/deployments/chain-11155111/build-info/solc-0_8_28-0a18893556a201a54858b5d523ac1037fb68d670.json new file mode 100644 index 00000000..92a5d2af --- /dev/null +++ b/assignments/assign7todo/ignition/deployments/chain-11155111/build-info/solc-0_8_28-0a18893556a201a54858b5d523ac1037fb68d670.json @@ -0,0 +1,39 @@ +{ + "_format": "hh3-sol-build-info-1", + "id": "solc-0_8_28-0a18893556a201a54858b5d523ac1037fb68d670", + "solcVersion": "0.8.28", + "solcLongVersion": "0.8.28+commit.7893614a", + "userSourceNameMap": { + "contracts/Todo.sol": "project/contracts/Todo.sol" + }, + "input": { + "language": "Solidity", + "settings": { + "evmVersion": "cancun", + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "": [ + "ast" + ], + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ] + } + }, + "remappings": [] + }, + "sources": { + "project/contracts/Todo.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ncontract Todo{\n uint256 todoCounter;\n\n enum Status{\n Pending,\n Done,\n Cancelled,\n Defaulted\n }\n\n struct TodoList{\n uint id;\n address owner;\n string text;\n Status status;\n uint256 deadline;\n }\n\n mapping(uint => TodoList) todos;\n\n event TodoCreated(string text, uint deadline);\n\n\n\nfunction createTodo(string memory _text, uint _deadline) external returns(uint){\n require(bytes(_text).length > 0, \"Empty text\");\n require(_deadline > (block.timestamp + 600), \"Invalid deadline\");\n require(msg.sender != address(0), \"Zero address\");\n\n todoCounter++;\n\n todos[todoCounter] = TodoList(todoCounter, msg.sender, _text, Status.Pending, _deadline);\n\n emit TodoCreated(_text, _deadline);\n return todoCounter; \n}\n\nfunction markAsDone(uint _id) external {\n require((_id > 0) && (_id <= todoCounter) , 'invalid id');\n TodoList storage todo = todos[_id];\n require(todo.status == Status.Pending, \"Not pending\");\n require(msg.sender == todo.owner, \"unauthorized Caller\");\n\n if(block.timestamp > todo.deadline){\n todo.status = Status.Defaulted;\n }\n else{\n todo.status = Status.Done;\n }\n\n}\n\n}" + } + } + } +} \ No newline at end of file diff --git a/assignments/assign7todo/ignition/deployments/chain-11155111/deployed_addresses.json b/assignments/assign7todo/ignition/deployments/chain-11155111/deployed_addresses.json new file mode 100644 index 00000000..a4d68923 --- /dev/null +++ b/assignments/assign7todo/ignition/deployments/chain-11155111/deployed_addresses.json @@ -0,0 +1,3 @@ +{ + "TodoModule#Todo": "0x458554d760ee2C80e47B1f2336209C457887859a" +} \ No newline at end of file diff --git a/assignments/assign7todo/ignition/deployments/chain-11155111/journal.jsonl b/assignments/assign7todo/ignition/deployments/chain-11155111/journal.jsonl new file mode 100644 index 00000000..ac9d62c8 --- /dev/null +++ b/assignments/assign7todo/ignition/deployments/chain-11155111/journal.jsonl @@ -0,0 +1,8 @@ + +{"chainId":11155111,"type":"DEPLOYMENT_INITIALIZE"} +{"artifactId":"TodoModule#Todo","constructorArgs":[],"contractName":"Todo","dependencies":[],"from":"0xce720e05fbc3a1aa9fe798feec55733034e98544","futureId":"TodoModule#Todo","futureType":"NAMED_ARTIFACT_CONTRACT_DEPLOYMENT","libraries":{},"strategy":"basic","strategyConfig":{},"type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"0"}} +{"futureId":"TodoModule#Todo","networkInteraction":{"data":"0x6080604052348015600e575f5ffd5b506106568061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063d74de14d14610038578063ece28c6c1461004d575b5f5ffd5b61004b610046366004610372565b610072565b005b61006061005b36600461039d565b6101a4565b60405190815260200160405180910390f35b5f8111801561008257505f548111155b6100c05760405162461bcd60e51b815260206004820152600a6024820152691a5b9d985b1a59081a5960b21b60448201526064015b60405180910390fd5b5f8181526001602052604081209060038083015460ff16908111156100e7576100e7610452565b146101225760405162461bcd60e51b815260206004820152600b60248201526a4e6f742070656e64696e6760a81b60448201526064016100b7565b60018101546001600160a01b031633146101745760405162461bcd60e51b81526020600482015260136024820152723ab730baba3437b934bd32b21021b0b63632b960691b60448201526064016100b7565b8060040154421115610193576003908101805460ff1916909117905550565b600301805460ff1916600117905550565b5f5f8351116101e25760405162461bcd60e51b815260206004820152600a602482015269115b5c1d1e481d195e1d60b21b60448201526064016100b7565b6101ee4261025861047a565b821161022f5760405162461bcd60e51b815260206004820152601060248201526f496e76616c696420646561646c696e6560801b60448201526064016100b7565b3361026b5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b60448201526064016100b7565b5f805490806102798361048d565b90915550506040805160a0810182525f80548252336020830152918101859052906060820190815260209081018490525f805481526001808352604091829020845181559284015190830180546001600160a01b0319166001600160a01b0390921691909117905582015160028201906102f39082610529565b506060820151816003015f6101000a81548160ff0219169083600381111561031d5761031d610452565b0217905550608082015181600401559050507f022c3fffe570decf2328dbf4f2af598df5112da7e31568af8b927c48276ccae383836040516103609291906105e4565b60405180910390a1505f545b92915050565b5f60208284031215610382575f5ffd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156103ae575f5ffd5b823567ffffffffffffffff8111156103c4575f5ffd5b8301601f810185136103d4575f5ffd5b803567ffffffffffffffff8111156103ee576103ee610389565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561041d5761041d610389565b604052818152828201602001871015610434575f5ffd5b816020840160208301375f6020928201830152969401359450505050565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8082018082111561036c5761036c610466565b5f6001820161049e5761049e610466565b5060010190565b600181811c908216806104b957607f821691505b6020821081036104d757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561052457805f5260205f20601f840160051c810160208510156105025750805b601f840160051c820191505b81811015610521575f815560010161050e565b50505b505050565b815167ffffffffffffffff81111561054357610543610389565b6105578161055184546104a5565b846104dd565b6020601f821160018114610589575f83156105725750848201515b5f19600385901b1c1916600184901b178455610521565b5f84815260208120601f198516915b828110156105b85787850151825560209485019460019092019101610598565b50848210156105d557868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b604081525f83518060408401528060208601606085015e5f606082850101526060601f19601f830116840101915050826020830152939250505056fea2646970667358221220422aab76da81c357c07497ea804246ba9bc2ff7312712e4fc2334e7254ba51da64736f6c634300081c0033","id":1,"type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"0"}},"type":"NETWORK_INTERACTION_REQUEST"} +{"futureId":"TodoModule#Todo","networkInteractionId":1,"nonce":0,"type":"TRANSACTION_PREPARE_SEND"} +{"futureId":"TodoModule#Todo","networkInteractionId":1,"nonce":0,"transaction":{"fees":{"maxFeePerGas":{"_kind":"bigint","value":"2085932911"},"maxPriorityFeePerGas":{"_kind":"bigint","value":"1439189"}},"hash":"0x844cfaca7887a79073cc0aa15761e07047e727efc534af7df320767b9415777f"},"type":"TRANSACTION_SEND"} +{"futureId":"TodoModule#Todo","hash":"0x844cfaca7887a79073cc0aa15761e07047e727efc534af7df320767b9415777f","networkInteractionId":1,"receipt":{"blockHash":"0x93922fcc7430cf6410400892b0372368f43e10ba57b0d1c73047c40e8b0566e6","blockNumber":10238391,"contractAddress":"0x458554d760ee2C80e47B1f2336209C457887859a","logs":[],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"} +{"futureId":"TodoModule#Todo","result":{"address":"0x458554d760ee2C80e47B1f2336209C457887859a","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"} \ No newline at end of file diff --git a/assignments/assign7todo/ignition/modules/Todo.ts b/assignments/assign7todo/ignition/modules/Todo.ts new file mode 100644 index 00000000..ed33dcd2 --- /dev/null +++ b/assignments/assign7todo/ignition/modules/Todo.ts @@ -0,0 +1,10 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; + +export default buildModule("TodoModule", (m) => { + const todo = m.contract("Todo"); + + + //m.call(counter, "incBy", [5n]); + + return { todo }; +}); diff --git a/assignments/assign7todo/package.json b/assignments/assign7todo/package.json new file mode 100644 index 00000000..508a8d12 --- /dev/null +++ b/assignments/assign7todo/package.json @@ -0,0 +1,23 @@ +{ + "name": "todo", + "version": "1.0.0", + "type": "module", + "devDependencies": { + "@nomicfoundation/hardhat-ethers": "^4.0.4", + "@nomicfoundation/hardhat-ignition": "^3.0.7", + "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.2", + "@types/chai": "^4.3.20", + "@types/chai-as-promised": "^8.0.2", + "@types/mocha": "^10.0.10", + "@types/node": "^22.19.8", + "chai": "^5.3.3", + "ethers": "^6.16.0", + "forge-std": "github:foundry-rs/forge-std#v1.9.4", + "hardhat": "^3.1.6", + "mocha": "^11.7.5", + "typescript": "~5.8.0" + }, + "dependencies": { + "dotenv": "^17.2.4" + } +} diff --git a/assignments/assign7todo/scripts/send-op-tx.ts b/assignments/assign7todo/scripts/send-op-tx.ts new file mode 100644 index 00000000..c10a2360 --- /dev/null +++ b/assignments/assign7todo/scripts/send-op-tx.ts @@ -0,0 +1,22 @@ +import { network } from "hardhat"; + +const { ethers } = await network.connect({ + network: "hardhatOp", + chainType: "op", +}); + +console.log("Sending transaction using the OP chain type"); + +const [sender] = await ethers.getSigners(); + +console.log("Sending 1 wei from", sender.address, "to itself"); + +console.log("Sending L2 transaction"); +const tx = await sender.sendTransaction({ + to: sender.address, + value: 1n, +}); + +await tx.wait(); + +console.log("Transaction sent successfully"); diff --git a/assignments/assign7todo/test/Counter.ts b/assignments/assign7todo/test/Counter.ts new file mode 100644 index 00000000..f8c38986 --- /dev/null +++ b/assignments/assign7todo/test/Counter.ts @@ -0,0 +1,36 @@ +import { expect } from "chai"; +import { network } from "hardhat"; + +const { ethers } = await network.connect(); + +describe("Counter", function () { + it("Should emit the Increment event when calling the inc() function", async function () { + const counter = await ethers.deployContract("Counter"); + + await expect(counter.inc()).to.emit(counter, "Increment").withArgs(1n); + }); + + it("The sum of the Increment events should match the current value", async function () { + const counter = await ethers.deployContract("Counter"); + const deploymentBlockNumber = await ethers.provider.getBlockNumber(); + + // run a series of increments + for (let i = 1; i <= 10; i++) { + await counter.incBy(i); + } + + const events = await counter.queryFilter( + counter.filters.Increment(), + deploymentBlockNumber, + "latest", + ); + + // check that the aggregated events match the current value + let total = 0n; + for (const event of events) { + total += event.args.by; + } + + expect(await counter.x()).to.equal(total); + }); +}); diff --git a/assignments/assign7todo/tsconfig.json b/assignments/assign7todo/tsconfig.json new file mode 100644 index 00000000..9b1380cc --- /dev/null +++ b/assignments/assign7todo/tsconfig.json @@ -0,0 +1,13 @@ +/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */ +{ + "compilerOptions": { + "lib": ["es2023"], + "module": "node16", + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "node16", + "outDir": "dist" + } +} From 91464279757ffeafb79df63c1b9c878d9a4341e3 Mon Sep 17 00:00:00 2001 From: JEREMIAH PETER Date: Mon, 16 Feb 2026 18:41:35 +0100 Subject: [PATCH 4/4] feat: submitting assignment 8 - escrow --- assignments/assign8escrow/.gitignore | 20 ++++ assignments/assign8escrow/README.md | 57 ++++++++++++ .../assign8escrow/contracts/Counter.sol | 19 ++++ .../assign8escrow/contracts/Counter.t.sol | 32 +++++++ assignments/assign8escrow/contracts/escro.sol | 93 +++++++++++++++++++ .../assign8escrow/contracts/escrotime.sol | 48 ++++++++++ .../assign8escrow/contracts/freelancer | 0 assignments/assign8escrow/hardhat.config.ts | 38 ++++++++ .../assign8escrow/ignition/modules/Counter.ts | 9 ++ assignments/assign8escrow/package.json | 20 ++++ .../assign8escrow/scripts/send-op-tx.ts | 22 +++++ assignments/assign8escrow/test/Counter.ts | 36 +++++++ assignments/assign8escrow/tsconfig.json | 13 +++ 13 files changed, 407 insertions(+) create mode 100644 assignments/assign8escrow/.gitignore create mode 100644 assignments/assign8escrow/README.md create mode 100644 assignments/assign8escrow/contracts/Counter.sol create mode 100644 assignments/assign8escrow/contracts/Counter.t.sol create mode 100644 assignments/assign8escrow/contracts/escro.sol create mode 100644 assignments/assign8escrow/contracts/escrotime.sol create mode 100644 assignments/assign8escrow/contracts/freelancer create mode 100644 assignments/assign8escrow/hardhat.config.ts create mode 100644 assignments/assign8escrow/ignition/modules/Counter.ts create mode 100644 assignments/assign8escrow/package.json create mode 100644 assignments/assign8escrow/scripts/send-op-tx.ts create mode 100644 assignments/assign8escrow/test/Counter.ts create mode 100644 assignments/assign8escrow/tsconfig.json diff --git a/assignments/assign8escrow/.gitignore b/assignments/assign8escrow/.gitignore new file mode 100644 index 00000000..991a319e --- /dev/null +++ b/assignments/assign8escrow/.gitignore @@ -0,0 +1,20 @@ +# Node modules +/node_modules + +# Compilation output +/dist + +# pnpm deploy output +/bundle + +# Hardhat Build Artifacts +/artifacts + +# Hardhat compilation (v2) support directory +/cache + +# Typechain output +/types + +# Hardhat coverage reports +/coverage diff --git a/assignments/assign8escrow/README.md b/assignments/assign8escrow/README.md new file mode 100644 index 00000000..968246e9 --- /dev/null +++ b/assignments/assign8escrow/README.md @@ -0,0 +1,57 @@ +# Sample Hardhat 3 Beta Project (`mocha` and `ethers`) + +This project showcases a Hardhat 3 Beta project using `mocha` for tests and the `ethers` library for Ethereum interactions. + +To learn more about the Hardhat 3 Beta, please visit the [Getting Started guide](https://hardhat.org/docs/getting-started#getting-started-with-hardhat-3). To share your feedback, join our [Hardhat 3 Beta](https://hardhat.org/hardhat3-beta-telegram-group) Telegram group or [open an issue](https://github.com/NomicFoundation/hardhat/issues/new) in our GitHub issue tracker. + +## Project Overview + +This example project includes: + +- A simple Hardhat configuration file. +- Foundry-compatible Solidity unit tests. +- TypeScript integration tests using `mocha` and ethers.js +- Examples demonstrating how to connect to different types of networks, including locally simulating OP mainnet. + +## Usage + +### Running Tests + +To run all the tests in the project, execute the following command: + +```shell +npx hardhat test +``` + +You can also selectively run the Solidity or `mocha` tests: + +```shell +npx hardhat test solidity +npx hardhat test mocha +``` + +### Make a deployment to Sepolia + +This project includes an example Ignition module to deploy the contract. You can deploy this module to a locally simulated chain or to Sepolia. + +To run the deployment to a local chain: + +```shell +npx hardhat ignition deploy ignition/modules/Counter.ts +``` + +To run the deployment to Sepolia, you need an account with funds to send the transaction. The provided Hardhat configuration includes a Configuration Variable called `SEPOLIA_PRIVATE_KEY`, which you can use to set the private key of the account you want to use. + +You can set the `SEPOLIA_PRIVATE_KEY` variable using the `hardhat-keystore` plugin or by setting it as an environment variable. + +To set the `SEPOLIA_PRIVATE_KEY` config variable using `hardhat-keystore`: + +```shell +npx hardhat keystore set SEPOLIA_PRIVATE_KEY +``` + +After setting the variable, you can run the deployment with the Sepolia network: + +```shell +npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts +``` diff --git a/assignments/assign8escrow/contracts/Counter.sol b/assignments/assign8escrow/contracts/Counter.sol new file mode 100644 index 00000000..8d00cb7c --- /dev/null +++ b/assignments/assign8escrow/contracts/Counter.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +contract Counter { + uint public x; + + event Increment(uint by); + + function inc() public { + x++; + emit Increment(1); + } + + function incBy(uint by) public { + require(by > 0, "incBy: increment should be positive"); + x += by; + emit Increment(by); + } +} diff --git a/assignments/assign8escrow/contracts/Counter.t.sol b/assignments/assign8escrow/contracts/Counter.t.sol new file mode 100644 index 00000000..ac71d5b8 --- /dev/null +++ b/assignments/assign8escrow/contracts/Counter.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import {Counter} from "./Counter.sol"; +import {Test} from "forge-std/Test.sol"; + +// Solidity tests are compatible with foundry, so they +// use the same syntax and offer the same functionality. + +contract CounterTest is Test { + Counter counter; + + function setUp() public { + counter = new Counter(); + } + + function test_InitialValue() public view { + require(counter.x() == 0, "Initial value should be 0"); + } + + function testFuzz_Inc(uint8 x) public { + for (uint8 i = 0; i < x; i++) { + counter.inc(); + } + require(counter.x() == x, "Value after calling inc x times should be x"); + } + + function test_IncByZero() public { + vm.expectRevert(); + counter.incBy(0); + } +} diff --git a/assignments/assign8escrow/contracts/escro.sol b/assignments/assign8escrow/contracts/escro.sol new file mode 100644 index 00000000..2ef8de3e --- /dev/null +++ b/assignments/assign8escrow/contracts/escro.sol @@ -0,0 +1,93 @@ + // SPDX-License-Identifier: MIT + pragma solidity 0.8.28; + +contract EscrowWithTimeout { + + //ROLES + + address public buyer; + address public seller; + address public escrowAgent; + + //ESCROW STATES + + enum EscrowState { + AWAITING_PAYMENT, + AWAITING_DELIVERY, + COMPLETE + } + + EscrowState public state; + + + //TIMEOUT VARIABLES + uint256 public depositTime; + uint256 public deliveryDeadline; + + // Seller has 2 days to deliver + uint256 public constant DELIVERY_TIME_LIMIT = 2 days; + + constructor(address _buyer, address _seller) { + buyer = _buyer; + seller = _seller; + escrowAgent = msg.sender; + + state = EscrowState.AWAITING_PAYMENT; + } + + + //BUYER DEPOSITS ETHER + + + function deposit() external payable { + require(msg.sender == buyer, "Only buyer can deposit"); + require(state == EscrowState.AWAITING_PAYMENT, "Already paid"); + require(msg.value > 0, "Must send Ether"); + + // Record the time of deposit + depositTime = block.timestamp; + + // Set delivery deadline + deliveryDeadline = block.timestamp + 172800; + + state = EscrowState.AWAITING_DELIVERY; + } + + + //SELLER CONFIRMS DELIVERY + + function confirmDelivery() external { + require(msg.sender == seller, "Only seller"); + require(state == EscrowState.AWAITING_DELIVERY, "Not awaiting delivery"); + + // Must deliver before deadline + require(block.timestamp <= deliveryDeadline, "Delivery time expired"); + + state = EscrowState.COMPLETE; + } + + + //ESCROW AGENT RELEASES FUNDS + + function releaseFunds() external { + require(msg.sender == escrowAgent, "Only escrow agent"); + require(state == EscrowState.COMPLETE, "Escrow not complete"); + + payable(seller).transfer(address(this).balance); + } + + + //ESCROW AGENT REFUNDS BUYER + + function refundBuyer() external { + require(msg.sender == escrowAgent, "Only escrow agent"); + require(state == EscrowState.AWAITING_DELIVERY, "Cannot refund now"); + + // Refund only allowed AFTER deadline + require(block.timestamp > deliveryDeadline, "Delivery time not expired"); + + state = EscrowState.COMPLETE; + + payable(buyer).transfer(address(this).balance); + } +} diff --git a/assignments/assign8escrow/contracts/escrotime.sol b/assignments/assign8escrow/contracts/escrotime.sol new file mode 100644 index 00000000..acb10260 --- /dev/null +++ b/assignments/assign8escrow/contracts/escrotime.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./escro.sol"; + +contract EscrowFactory { + address[] public escrows; + + event EscrowCreated( + address escrow, + address buyer, + address seller, + address agent, + uint256 amount + ); + + function createEscrow( + address _seller, + address _agent + ) external payable { + require(msg.value > 0, "Send ETH to escrow"); + + EscrowWithTimeout escrow = new EscrowWithTimeout( + msg.sender, // buyer + _seller + ); + + // Transfer the ETH to the escrow contract and call deposit + escrow.deposit{value: msg.value}(); + + escrows.push(address(escrow)); + + emit EscrowCreated( + address(escrow), + msg.sender, + _seller, + _agent, + msg.value + ); + + } + + function getEscrows() external view returns (address[] memory) { + return escrows; + } + + +} \ No newline at end of file diff --git a/assignments/assign8escrow/contracts/freelancer b/assignments/assign8escrow/contracts/freelancer new file mode 100644 index 00000000..e69de29b diff --git a/assignments/assign8escrow/hardhat.config.ts b/assignments/assign8escrow/hardhat.config.ts new file mode 100644 index 00000000..7092b852 --- /dev/null +++ b/assignments/assign8escrow/hardhat.config.ts @@ -0,0 +1,38 @@ +import hardhatToolboxMochaEthersPlugin from "@nomicfoundation/hardhat-toolbox-mocha-ethers"; +import { configVariable, defineConfig } from "hardhat/config"; + +export default defineConfig({ + plugins: [hardhatToolboxMochaEthersPlugin], + solidity: { + profiles: { + default: { + version: "0.8.28", + }, + production: { + version: "0.8.28", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + }, + }, + networks: { + hardhatMainnet: { + type: "edr-simulated", + chainType: "l1", + }, + hardhatOp: { + type: "edr-simulated", + chainType: "op", + }, + sepolia: { + type: "http", + chainType: "l1", + url: configVariable("SEPOLIA_RPC_URL"), + accounts: [configVariable("SEPOLIA_PRIVATE_KEY")], + }, + }, +}); diff --git a/assignments/assign8escrow/ignition/modules/Counter.ts b/assignments/assign8escrow/ignition/modules/Counter.ts new file mode 100644 index 00000000..042e61c8 --- /dev/null +++ b/assignments/assign8escrow/ignition/modules/Counter.ts @@ -0,0 +1,9 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; + +export default buildModule("CounterModule", (m) => { + const counter = m.contract("Counter"); + + m.call(counter, "incBy", [5n]); + + return { counter }; +}); diff --git a/assignments/assign8escrow/package.json b/assignments/assign8escrow/package.json new file mode 100644 index 00000000..61a6eb73 --- /dev/null +++ b/assignments/assign8escrow/package.json @@ -0,0 +1,20 @@ +{ + "name": "assignt2", + "version": "1.0.0", + "type": "module", + "devDependencies": { + "@nomicfoundation/hardhat-ethers": "^4.0.4", + "@nomicfoundation/hardhat-ignition": "^3.0.7", + "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.2", + "@types/chai": "^4.3.20", + "@types/chai-as-promised": "^8.0.2", + "@types/mocha": "^10.0.10", + "@types/node": "^22.19.8", + "chai": "^5.3.3", + "ethers": "^6.16.0", + "forge-std": "github:foundry-rs/forge-std#v1.9.4", + "hardhat": "^3.1.6", + "mocha": "^11.7.5", + "typescript": "~5.8.0" + } +} diff --git a/assignments/assign8escrow/scripts/send-op-tx.ts b/assignments/assign8escrow/scripts/send-op-tx.ts new file mode 100644 index 00000000..c10a2360 --- /dev/null +++ b/assignments/assign8escrow/scripts/send-op-tx.ts @@ -0,0 +1,22 @@ +import { network } from "hardhat"; + +const { ethers } = await network.connect({ + network: "hardhatOp", + chainType: "op", +}); + +console.log("Sending transaction using the OP chain type"); + +const [sender] = await ethers.getSigners(); + +console.log("Sending 1 wei from", sender.address, "to itself"); + +console.log("Sending L2 transaction"); +const tx = await sender.sendTransaction({ + to: sender.address, + value: 1n, +}); + +await tx.wait(); + +console.log("Transaction sent successfully"); diff --git a/assignments/assign8escrow/test/Counter.ts b/assignments/assign8escrow/test/Counter.ts new file mode 100644 index 00000000..f8c38986 --- /dev/null +++ b/assignments/assign8escrow/test/Counter.ts @@ -0,0 +1,36 @@ +import { expect } from "chai"; +import { network } from "hardhat"; + +const { ethers } = await network.connect(); + +describe("Counter", function () { + it("Should emit the Increment event when calling the inc() function", async function () { + const counter = await ethers.deployContract("Counter"); + + await expect(counter.inc()).to.emit(counter, "Increment").withArgs(1n); + }); + + it("The sum of the Increment events should match the current value", async function () { + const counter = await ethers.deployContract("Counter"); + const deploymentBlockNumber = await ethers.provider.getBlockNumber(); + + // run a series of increments + for (let i = 1; i <= 10; i++) { + await counter.incBy(i); + } + + const events = await counter.queryFilter( + counter.filters.Increment(), + deploymentBlockNumber, + "latest", + ); + + // check that the aggregated events match the current value + let total = 0n; + for (const event of events) { + total += event.args.by; + } + + expect(await counter.x()).to.equal(total); + }); +}); diff --git a/assignments/assign8escrow/tsconfig.json b/assignments/assign8escrow/tsconfig.json new file mode 100644 index 00000000..9b1380cc --- /dev/null +++ b/assignments/assign8escrow/tsconfig.json @@ -0,0 +1,13 @@ +/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */ +{ + "compilerOptions": { + "lib": ["es2023"], + "module": "node16", + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "node16", + "outDir": "dist" + } +}