From 075ad406219c328a223542ec112cc66ad215d2db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 18:01:47 +0000 Subject: [PATCH 1/3] Initial plan From fe0c5f38495f804f636db546ef54a2a588c9a2f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 18:14:03 +0000 Subject: [PATCH 2/3] Create comprehensive dApp starter repository with contracts, frontend, tests, and documentation Co-authored-by: wessel05j <146479070+wessel05j@users.noreply.github.com> --- .env.example | 9 + .github/workflows/test.yml | 52 +++++ .gitignore | 44 ++++ FAQ.md | 213 ++++++++++++++++++ GLOSSARY.md | 242 +++++++++++++++++++++ QUICKSTART.md | 202 +++++++++++++++++ README.md | 170 ++++++++++++++- RESOURCES.md | 193 +++++++++++++++++ SECURITY.md | 122 +++++++++++ contracts/MyToken.sol | 29 +++ contracts/SimpleStorage.sol | 32 +++ docs/CONTRACTS.md | 296 +++++++++++++++++++++++++ docs/CONTRIBUTING.md | 211 ++++++++++++++++++ docs/DEPLOYMENT.md | 387 +++++++++++++++++++++++++++++++++ docs/FRONTEND.md | 418 ++++++++++++++++++++++++++++++++++++ docs/SETUP.md | 212 ++++++++++++++++++ frontend/css/style.css | 189 ++++++++++++++++ frontend/index.html | 62 ++++++ frontend/js/app.js | 221 +++++++++++++++++++ hardhat.config.js | 34 +++ package.json | 32 +++ scripts/deploy.js | 53 +++++ test/MyToken.test.js | 63 ++++++ test/SimpleStorage.test.js | 41 ++++ 24 files changed, 3525 insertions(+), 2 deletions(-) create mode 100644 .env.example create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 FAQ.md create mode 100644 GLOSSARY.md create mode 100644 QUICKSTART.md create mode 100644 RESOURCES.md create mode 100644 SECURITY.md create mode 100644 contracts/MyToken.sol create mode 100644 contracts/SimpleStorage.sol create mode 100644 docs/CONTRACTS.md create mode 100644 docs/CONTRIBUTING.md create mode 100644 docs/DEPLOYMENT.md create mode 100644 docs/FRONTEND.md create mode 100644 docs/SETUP.md create mode 100644 frontend/css/style.css create mode 100644 frontend/index.html create mode 100644 frontend/js/app.js create mode 100644 hardhat.config.js create mode 100644 package.json create mode 100644 scripts/deploy.js create mode 100644 test/MyToken.test.js create mode 100644 test/SimpleStorage.test.js diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0551e58 --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +# Network RPC URLs +SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_ALCHEMY_KEY +MAINNET_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_KEY + +# Private key for deployment (NEVER commit your real private key!) +PRIVATE_KEY=your_private_key_here + +# Etherscan API key for contract verification +ETHERSCAN_API_KEY=your_etherscan_api_key_here diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..e878eaa --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,52 @@ +name: Smart Contract CI + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Compile contracts + run: npm run compile + + - name: Run tests + run: npm test + + - name: Check contract size + run: npx hardhat size-contracts || echo "Size check skipped" + continue-on-error: true + + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run Solidity linter + run: npx solhint 'contracts/**/*.sol' || echo "Linting skipped" + continue-on-error: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2782f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# Dependencies +node_modules/ +package-lock.json + +# Environment variables +.env +.env.local +.env.production + +# Build outputs +dist/ +build/ +cache/ +artifacts/ + +# Hardhat files +coverage/ +typechain/ +typechain-types/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Testing +coverage.json + +# Temporary files +*.tmp +.cache/ diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000..c70aee7 --- /dev/null +++ b/FAQ.md @@ -0,0 +1,213 @@ +# FAQ - Frequently Asked Questions + +## General Questions + +### What is a dApp? +A dApp (decentralized application) is an application that runs on a blockchain network instead of centralized servers. It typically consists of smart contracts (backend) and a web interface (frontend). + +### What is Ethereum? +Ethereum is a blockchain platform that allows developers to build and deploy smart contracts and dApps. It has its own cryptocurrency called Ether (ETH). + +### What is a smart contract? +A smart contract is code that runs on the blockchain. Once deployed, it executes automatically when certain conditions are met, without needing a middleman. + +### Do I need to know blockchain to start? +No! This starter repository is designed for beginners. Basic JavaScript knowledge helps, but you can learn as you go. + +## Setup Questions + +### Why do I need Node.js? +Node.js lets you run JavaScript on your computer. We use it to run development tools like Hardhat and to manage project dependencies. + +### What is MetaMask? +MetaMask is a browser extension that acts as a cryptocurrency wallet. It lets you interact with dApps and sign transactions. + +### Do I need real money to test? +No! You can use: +- Local blockchain (completely free, no real money) +- Testnets with free test ETH (not real money) +- Only need real ETH for mainnet deployment + +### How do I get test ETH? +Visit a faucet website like: +- Sepolia: [sepoliafaucet.com](https://sepoliafaucet.com/) +- Goerli: [goerlifaucet.com](https://goerlifaucet.com/) + +Enter your wallet address and receive free test ETH. + +## Development Questions + +### What is Hardhat? +Hardhat is a development environment for Ethereum. It helps you: +- Compile smart contracts +- Run tests +- Deploy contracts +- Debug code + +### What is Solidity? +Solidity is the programming language used to write smart contracts for Ethereum. It's similar to JavaScript and C++. + +### Why use OpenZeppelin? +OpenZeppelin provides secure, tested smart contract templates. Instead of writing everything from scratch, you can use their battle-tested code. + +### What is gas? +Gas is the fee paid to execute transactions or run smart contracts on Ethereum. It's paid in ETH and goes to miners/validators. + +### How much does deployment cost? +Costs vary based on: +- Network (local = free, testnet = free, mainnet = $$$) +- Gas prices (changes constantly) +- Contract complexity + +Example mainnet costs (approximate): +- Simple contract: $5-50 +- Complex contract: $50-500+ + +### Can I change a smart contract after deployment? +No! Smart contracts are immutable once deployed. Plan carefully and test thoroughly. You can: +- Deploy a new version +- Use upgradeable contract patterns (advanced) + +## Usage Questions + +### Why did my transaction fail? +Common reasons: +- Out of gas (increase gas limit) +- Contract error (check error message) +- Wrong network (switch to correct network) +- Insufficient funds + +### What's the difference between view and public functions? +- `view`: Only reads data, doesn't change state, FREE to call +- `public`: Can change state, costs gas, needs transaction + +### How do I test my contracts? +```bash +npm test +``` + +Tests are in the `test/` folder. Add new tests for new features. + +### How do I deploy to testnet? +1. Get test ETH from faucet +2. Configure `.env` with RPC URL and private key +3. Run `npm run deploy:testnet` + +## Troubleshooting + +### "Error: Cannot find module" +```bash +rm -rf node_modules package-lock.json +npm install +``` + +### "Network timeout" +- Check your internet connection +- Try different RPC provider +- Increase timeout in `hardhat.config.js` + +### "Transaction underpriced" +- Increase gas price +- Wait and try again (gas prices fluctuate) + +### "Nonce too low" +- Clear pending transactions in MetaMask +- Reset account in MetaMask settings + +### MetaMask not detecting my local network +- Make sure Hardhat node is running +- Check network settings (RPC URL, Chain ID) +- Try disconnecting and reconnecting + +### Frontend not updating after contract changes +- Redeploy contracts +- Update contract addresses in frontend +- Clear browser cache +- Hard refresh (Ctrl+Shift+R) + +## Security Questions + +### Is my private key safe? +- NEVER share your private key +- NEVER commit `.env` to git +- Use separate wallets for dev/production +- Keep main funds in hardware wallet + +### How do I secure my smart contracts? +- Use OpenZeppelin contracts +- Write comprehensive tests +- Get security audit before mainnet +- Follow security best practices +- Start with simple, well-tested patterns + +### What happens if I find a bug after deployment? +- You cannot change deployed contracts +- You may need to deploy a new version +- Have an emergency plan before deployment +- Consider using proxy patterns for upgrades + +## Cost Questions + +### How much does it cost to learn? +- This repository: FREE +- Local testing: FREE +- Testnet deployment: FREE +- Learning resources: Mostly FREE +- Mainnet deployment: Costs real ETH + +### What are typical gas costs? +Gas costs depend on network congestion: +- Low: 20-30 gwei +- Medium: 30-50 gwei +- High: 50-100+ gwei + +### Can I reduce gas costs? +Yes: +- Deploy during low-traffic times +- Optimize your code +- Use gas-efficient patterns +- Batch transactions +- Use Layer 2 solutions + +## Next Steps Questions + +### What should I learn next? +1. Master the basics (SimpleStorage) +2. Understand tokens (ERC20) +3. Try NFTs (ERC721) +4. Build a small project +5. Deploy to testnet +6. Learn advanced patterns + +### Where can I find help? +- Ethereum Stack Exchange +- Discord communities +- This repository's issues +- Reddit r/ethdev +- Twitter #ethereum + +### How long does it take to learn? +- Basics: 1-2 weeks +- Build first dApp: 1 month +- Comfortable with Solidity: 2-3 months +- Production-ready: 6+ months + +### Can I make money building dApps? +Yes! Opportunities include: +- Freelance development +- Full-time blockchain jobs +- Building your own projects +- Hackathon prizes +- Bug bounties +- Grants and funding + +## Still Have Questions? + +- Check the [documentation](./docs/) +- Read the [RESOURCES.md](./RESOURCES.md) +- Open an issue on GitHub +- Ask on Ethereum Stack Exchange + +--- + +Don't see your question? Open an issue and we'll add it! diff --git a/GLOSSARY.md b/GLOSSARY.md new file mode 100644 index 0000000..02b1aa6 --- /dev/null +++ b/GLOSSARY.md @@ -0,0 +1,242 @@ +# Glossary of Terms + +## A + +**ABI (Application Binary Interface)** +The interface description that allows external applications to interact with smart contracts. It defines function signatures and data types. + +**Address** +A unique identifier (like an account number) on the Ethereum blockchain. Example: `0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1` + +**Artifact** +Compiled output of a smart contract, including bytecode and ABI. + +## B + +**Block** +A collection of transactions bundled together and added to the blockchain. + +**Blockchain** +A distributed, immutable ledger that records transactions across many computers. + +**Bytecode** +Machine-readable code that smart contracts are compiled into before deployment. + +## C + +**Chain ID** +A unique identifier for an Ethereum network (e.g., 1 for mainnet, 1337 for local). + +**Constructor** +Special function that runs once when a smart contract is deployed. + +**Contract** +See "Smart Contract" + +## D + +**dApp (Decentralized Application)** +An application that runs on a blockchain network instead of centralized servers. + +**Deployment** +The process of publishing a smart contract to the blockchain. + +**Deployer** +The account that deploys a smart contract and usually has special permissions. + +## E + +**EOA (Externally Owned Account)** +A regular Ethereum account controlled by a private key (like your MetaMask wallet). + +**ERC (Ethereum Request for Comments)** +Standards for Ethereum smart contracts (e.g., ERC-20 for tokens, ERC-721 for NFTs). + +**ERC-20** +The standard for fungible tokens (like currencies). + +**ERC-721** +The standard for non-fungible tokens (NFTs). + +**Ether (ETH)** +The native cryptocurrency of the Ethereum blockchain. + +**Event** +A log emitted by a smart contract that external applications can listen to. + +**Etherscan** +A blockchain explorer for viewing transactions, contracts, and addresses. + +## F + +**Faucet** +A service that provides free test ETH for development. + +**Function** +A piece of code in a smart contract that performs a specific task. + +## G + +**Gas** +The fee required to execute transactions or run smart contracts on Ethereum. + +**Gas Limit** +The maximum amount of gas you're willing to spend on a transaction. + +**Gas Price** +The price per unit of gas, measured in gwei. + +**Gwei** +A denomination of ETH. 1 ETH = 1,000,000,000 gwei. + +## H + +**Hardhat** +A development environment for compiling, testing, and deploying smart contracts. + +**Hash** +A unique fingerprint of data. Used for transaction IDs and addresses. + +## I + +**Immutable** +Cannot be changed. Smart contracts are immutable once deployed. + +**Interface** +A contract definition that specifies function signatures without implementation. + +## L + +**Library** +Reusable code that can be used by multiple contracts. + +**Localhost** +Your local computer. Used for local blockchain testing. + +## M + +**Mainnet** +The main Ethereum network where real ETH has value. + +**Mapping** +A key-value data structure in Solidity (like a dictionary or hash table). + +**Metamask** +A popular browser wallet for managing Ethereum accounts. + +**Modifier** +Code that runs before/after a function to add conditions or change behavior. + +**Mint** +To create new tokens. + +## N + +**Network** +An Ethereum blockchain (mainnet, testnet, or local). + +**Node** +A computer that participates in the Ethereum network. + +**Nonce** +A counter for transactions from an account, ensures transactions are processed in order. + +## O + +**OpenZeppelin** +A library of secure, audited smart contract templates. + +**Oracle** +A service that provides external data to smart contracts. + +**Owner** +An address with special permissions in a contract. + +## P + +**Private Key** +Secret key that controls an Ethereum account. NEVER share this! + +**Provider** +A connection to an Ethereum node, used to read blockchain data. + +**Proxy** +A contract that delegates calls to another contract, enabling upgrades. + +**Public** +Accessible by anyone (opposite of private). + +## R + +**Reentrancy** +A vulnerability where a function can be called multiple times before completing. + +**Remix** +A browser-based IDE for writing and testing Solidity. + +**Require** +A statement that reverts a transaction if a condition is not met. + +**Revert** +To undo a transaction and return an error. + +**RPC (Remote Procedure Call)** +A protocol for communicating with Ethereum nodes. + +## S + +**Sepolia** +An Ethereum test network. + +**Signer** +An account that can sign and send transactions. + +**Smart Contract** +Self-executing code deployed on the blockchain. + +**Solidity** +The programming language for writing Ethereum smart contracts. + +**State** +The current data stored in a smart contract. + +**Storage** +Permanent data storage in a smart contract (expensive). + +## T + +**Testnet** +A blockchain network for testing (uses fake ETH). + +**Token** +A digital asset on the blockchain (can be fungible or non-fungible). + +**Transaction** +An action on the blockchain (transfer, contract call, etc.). + +**Transfer** +Moving tokens or ETH from one address to another. + +## U + +**Uint** +Unsigned integer (positive numbers only). `uint256` = 0 to 2^256-1. + +## V + +**View Function** +A function that only reads data, doesn't change state, and is free to call. + +## W + +**Wallet** +Software that manages your Ethereum accounts and private keys. + +**Wei** +The smallest unit of ETH. 1 ETH = 1,000,000,000,000,000,000 wei. + +## Need More Definitions? + +- Check the [Ethereum Glossary](https://ethereum.org/en/glossary/) +- Ask in our community +- Open an issue to request new terms diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..ecc4891 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,202 @@ +# Quick Start Guide + +Get started with your first dApp in under 10 minutes! + +## Step 1: Install Prerequisites (5 minutes) + +### Install Node.js +1. Go to [nodejs.org](https://nodejs.org/) +2. Download the LTS version +3. Run the installer +4. Verify: Open terminal and type `node --version` + +### Install MetaMask +1. Visit [metamask.io](https://metamask.io/) +2. Click "Download" +3. Add to your browser (Chrome, Firefox, or Brave) +4. Create a new wallet +5. **IMPORTANT**: Save your seed phrase somewhere safe! + +## Step 2: Set Up the Project (2 minutes) + +```bash +# Install dependencies +npm install + +# This installs: +# - Hardhat (Ethereum development environment) +# - Ethers.js (library to interact with Ethereum) +# - OpenZeppelin (secure smart contract library) +# - Chai (testing framework) +``` + +## Step 3: Compile Contracts (30 seconds) + +```bash +npm run compile +``` + +This compiles your Solidity smart contracts into bytecode that can run on Ethereum. + +## Step 4: Run Tests (30 seconds) + +```bash +npm test +``` + +All tests should pass โœ…. This verifies your contracts work correctly. + +## Step 5: Start Local Blockchain (30 seconds) + +Open a new terminal and run: + +```bash +npm run node +``` + +**Leave this running!** This creates a local Ethereum blockchain on your computer with: +- 20 test accounts +- 10,000 ETH each +- No real money involved + +## Step 6: Deploy Contracts (30 seconds) + +In a **new terminal**: + +```bash +npm run deploy:local +``` + +This deploys your smart contracts to your local blockchain. You'll see output like: + +``` +SimpleStorage deployed to: 0x5FbDB... +MyToken deployed to: 0xe7f1... +``` + +## Step 7: Connect MetaMask (1 minute) + +### Add Local Network to MetaMask + +1. Click MetaMask extension +2. Click network dropdown (usually says "Ethereum Mainnet") +3. Click "Add Network" โ†’ "Add a network manually" +4. Enter: + - **Network Name**: Localhost 8545 + - **RPC URL**: http://127.0.0.1:8545 + - **Chain ID**: 1337 + - **Currency Symbol**: ETH +5. Click "Save" + +### Import a Test Account + +1. Look at the terminal running `npm run node` +2. Find "Account #0" and copy the private key (starts with 0x...) +3. In MetaMask: Click account icon โ†’ "Import Account" +4. Paste the private key +5. Click "Import" + +You now have 10,000 test ETH! ๐Ÿ’ฐ + +## Step 8: Use the dApp (1 minute) + +1. Open `frontend/index.html` in your browser +2. Click "Connect Wallet" +3. Approve the connection in MetaMask +4. Try the features: + - Store a number in SimpleStorage + - Check your token balance + - Transfer tokens to another address + +## ๐ŸŽ‰ Congratulations! + +You've just: +- โœ… Set up a development environment +- โœ… Compiled smart contracts +- โœ… Deployed to a blockchain +- โœ… Created a working dApp + +## What's Next? + +### Learn More +- Read [docs/CONTRACTS.md](./docs/CONTRACTS.md) to understand the smart contracts +- Check [docs/FRONTEND.md](./docs/FRONTEND.md) to learn about the UI +- Explore [docs/SETUP.md](./docs/SETUP.md) for detailed setup options + +### Try These Challenges + +1. **Easy**: Change the stored number and see it update +2. **Medium**: Add a new function to increment the stored value +3. **Hard**: Create a new smart contract from scratch +4. **Expert**: Deploy to a real testnet (Sepolia) + +### Modify the Contracts + +1. Edit `contracts/SimpleStorage.sol` +2. Run `npm run compile` +3. Run `npm test` +4. Deploy again: `npm run deploy:local` +5. Refresh the frontend and test! + +## Common Issues + +### "Cannot connect to wallet" +- Make sure MetaMask is installed +- Click the MetaMask icon and unlock it +- Make sure you're on the "Localhost 8545" network + +### "Transaction failed" +- Check you're on the right network +- Make sure local node is still running +- Try refreshing the page + +### "Contract not found" +- Run `npm run deploy:local` again +- Make sure contract addresses in frontend match deployed addresses + +## Getting Help + +- Check the [main README](../README.md) +- Look at [docs/](./docs/) for detailed guides +- Open an issue on GitHub +- Ask on Ethereum Stack Exchange + +## Pro Tips ๐Ÿ’ก + +1. **Keep the local node running** while developing +2. **Check the browser console** (F12) for errors +3. **Read error messages** carefully - they usually tell you what's wrong +4. **Start simple** - master the basics before adding complexity +5. **Test often** - run tests after every change + +## Next Learning Steps + +1. **Week 1**: Understand how SimpleStorage works +2. **Week 2**: Modify MyToken to add new features +3. **Week 3**: Create a new contract (try a voting system) +4. **Week 4**: Deploy to Sepolia testnet +5. **Month 2**: Build your own dApp idea! + +## Recommended Learning Path + +### Beginner +- Modify existing contracts +- Add simple functions +- Change UI styling +- Deploy to testnet + +### Intermediate +- Create new contracts +- Use events and indexing +- Add access controls +- Integrate with libraries + +### Advanced +- Write complex logic +- Optimize gas usage +- Implement upgradeable contracts +- Build production dApps + +--- + +**Ready to dive deeper?** Check out the [full documentation](./docs/) or start coding! ๐Ÿš€ diff --git a/README.md b/README.md index b765412..407df99 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,168 @@ -# First-dApp -This is our attempt at starting to learn how to create dApps. We start out with a project like this to learn and understand the future of technology. +# First-dApp ๐Ÿš€ + +Welcome to your first decentralized application (dApp) starter repository! This project is designed to help you and your team learn blockchain development by providing a complete, working example of a dApp built on Ethereum. + +## ๐Ÿ“š What You'll Learn + +- How to write and deploy smart contracts using Solidity +- How to test smart contracts with Hardhat +- How to build a frontend that interacts with blockchain +- How to use MetaMask for wallet connections +- The basics of ERC20 tokens +- Best practices for dApp development + +## ๐ŸŽฏ What's Included + +This repository contains: + +- **Smart Contracts**: Two example contracts (SimpleStorage and MyToken) +- **Tests**: Complete test suites for both contracts +- **Deployment Scripts**: Automated deployment to local and test networks +- **Frontend**: A user-friendly web interface to interact with your contracts +- **Development Tools**: Hardhat configuration for professional development + +## ๐Ÿ—๏ธ Project Structure + +``` +First-dApp/ +โ”œโ”€โ”€ contracts/ # Smart contracts written in Solidity +โ”‚ โ”œโ”€โ”€ SimpleStorage.sol # Basic storage contract +โ”‚ โ””โ”€โ”€ MyToken.sol # ERC20 token contract +โ”œโ”€โ”€ test/ # Test files for smart contracts +โ”‚ โ”œโ”€โ”€ SimpleStorage.test.js +โ”‚ โ””โ”€โ”€ MyToken.test.js +โ”œโ”€โ”€ scripts/ # Deployment and utility scripts +โ”‚ โ””โ”€โ”€ deploy.js # Main deployment script +โ”œโ”€โ”€ frontend/ # Web interface for the dApp +โ”‚ โ”œโ”€โ”€ index.html +โ”‚ โ”œโ”€โ”€ css/ +โ”‚ โ””โ”€โ”€ js/ +โ”œโ”€โ”€ hardhat.config.js # Hardhat configuration +โ”œโ”€โ”€ package.json # Node.js dependencies +โ””โ”€โ”€ .env.example # Environment variables template +``` + +## ๐Ÿš€ Quick Start + +### Prerequisites + +Before you begin, make sure you have: +- [Node.js](https://nodejs.org/) (v16 or later) +- [MetaMask](https://metamask.io/) browser extension +- Basic understanding of JavaScript + +### Installation + +1. **Install dependencies** + ```bash + npm install + ``` + +2. **Set up environment variables** + ```bash + cp .env.example .env + # Edit .env with your values (for testnet deployment) + ``` + +3. **Compile contracts** + ```bash + npm run compile + ``` + +4. **Run tests** + ```bash + npm test + ``` + +5. **Start local blockchain** + ```bash + npm run node + ``` + Keep this running in a separate terminal. + +6. **Deploy contracts** (in a new terminal) + ```bash + npm run deploy:local + ``` + +7. **Open the frontend** + - Open `frontend/index.html` in your browser + - Connect your MetaMask wallet + - Make sure MetaMask is connected to localhost:8545 + - Start interacting with your dApp! + +## ๐Ÿ“– Detailed Documentation + +- [Setup Guide](./docs/SETUP.md) - Detailed setup instructions +- [Smart Contracts Guide](./docs/CONTRACTS.md) - Understanding the contracts +- [Frontend Guide](./docs/FRONTEND.md) - How the frontend works +- [Deployment Guide](./docs/DEPLOYMENT.md) - Deploy to testnets and mainnet +- [Contributing](./docs/CONTRIBUTING.md) - How to contribute + +## ๐Ÿงช Running Tests + +Run all tests: +```bash +npm test +``` + +Run tests with coverage: +```bash +npx hardhat coverage +``` + +## ๐Ÿ“ฆ Available Scripts + +- `npm run compile` - Compile smart contracts +- `npm test` - Run all tests +- `npm run node` - Start local Hardhat network +- `npm run deploy:local` - Deploy to local network +- `npm run deploy:testnet` - Deploy to Sepolia testnet +- `npm run clean` - Clean compiled artifacts + +## ๐Ÿ” Security + +- Never commit your `.env` file +- Never share your private keys +- Always test on testnets before mainnet +- Get your contracts audited before production use + +## ๐ŸŒŸ Next Steps + +Once you're comfortable with this starter: + +1. Modify the contracts to add your own features +2. Create new smart contracts +3. Enhance the frontend with more functionality +4. Deploy to Ethereum testnets (Sepolia, Goerli) +5. Learn about gas optimization +6. Explore DeFi, NFTs, and other use cases + +## ๐Ÿ“š Learning Resources + +- [Ethereum Documentation](https://ethereum.org/developers) +- [Solidity Documentation](https://docs.soliditylang.org/) +- [Hardhat Documentation](https://hardhat.org/docs) +- [OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts) +- [Ethers.js Documentation](https://docs.ethers.org/) + +## ๐Ÿค Contributing + +We welcome contributions! Please see [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for details. + +## ๐Ÿ“„ License + +This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details. + +## ๐Ÿ’ฌ Get Help + +- Check out the [docs](./docs/) folder +- Open an issue if you find bugs +- Join Ethereum developer communities +- Ask questions on Stack Overflow + +## ๐ŸŽ“ About This Project + +This is a learning project designed to help developers get started with blockchain development. It includes best practices and examples that you can build upon for your own projects. + +Happy coding! ๐Ÿš€ diff --git a/RESOURCES.md b/RESOURCES.md new file mode 100644 index 0000000..af6a225 --- /dev/null +++ b/RESOURCES.md @@ -0,0 +1,193 @@ +# Resources and Learning Materials + +## ๐Ÿ“š Official Documentation + +### Ethereum +- [Ethereum.org](https://ethereum.org/developers) - Official Ethereum documentation +- [Ethereum Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) - Technical specification +- [EIPs](https://eips.ethereum.org/) - Ethereum Improvement Proposals + +### Solidity +- [Solidity Docs](https://docs.soliditylang.org/) - Official language documentation +- [Solidity by Example](https://solidity-by-example.org/) - Learn by doing +- [Solidity Patterns](https://fravoll.github.io/solidity-patterns/) - Design patterns + +### Development Tools +- [Hardhat](https://hardhat.org/docs) - Development environment +- [Ethers.js](https://docs.ethers.org/) - JavaScript library +- [OpenZeppelin](https://docs.openzeppelin.com/) - Secure contracts library +- [Remix](https://remix.ethereum.org/) - Browser-based IDE + +## ๐ŸŽ“ Interactive Tutorials + +### Beginner +- [CryptoZombies](https://cryptozombies.io/) - Learn Solidity building a game +- [Buildspace](https://buildspace.so/) - Build projects, earn NFTs +- [LearnWeb3](https://learnweb3.io/) - Complete learning path +- [Questbook](https://www.questbook.app/) - Hands-on courses + +### Intermediate +- [Ethernaut](https://ethernaut.openzeppelin.com/) - Security challenges +- [Speed Run Ethereum](https://speedrunethereum.com/) - Build challenges +- [UseWeb3](https://www.useweb3.xyz/) - Curated resources + +### Advanced +- [Damn Vulnerable DeFi](https://www.damnvulnerabledefi.xyz/) - Security practice +- [Paradigm CTF](https://ctf.paradigm.xyz/) - Capture the flag challenges + +## ๐Ÿ“– Books + +- **"Mastering Ethereum"** by Andreas Antonopoulos +- **"The Infinite Machine"** by Camila Russo (History of Ethereum) +- **"Blockchain Basics"** by Daniel Drescher + +## ๐ŸŽฅ Video Courses + +### YouTube Channels +- [Patrick Collins](https://www.youtube.com/c/PatrickCollins) - Comprehensive tutorials +- [Dapp University](https://www.youtube.com/c/DappUniversity) +- [EatTheBlocks](https://www.youtube.com/c/EatTheBlocks) +- [Nader Dabit](https://www.youtube.com/c/naderdabit) + +### Paid Courses +- [Udemy - Ethereum and Solidity](https://www.udemy.com/topic/ethereum/) +- [Coursera - Blockchain Specialization](https://www.coursera.org/specializations/blockchain) + +## ๐Ÿ› ๏ธ Development Tools + +### IDEs & Editors +- [Visual Studio Code](https://code.visualstudio.com/) + Solidity extension +- [Remix IDE](https://remix.ethereum.org/) +- [Hardhat VSCode Extension](https://hardhat.org/hardhat-vscode) + +### Testing & Debugging +- [Hardhat](https://hardhat.org/) - Development environment +- [Ganache](https://trufflesuite.com/ganache/) - Local blockchain +- [Tenderly](https://tenderly.co/) - Monitoring and debugging + +### Security Tools +- [Slither](https://github.com/crytic/slither) - Static analyzer +- [Mythril](https://github.com/ConsenSys/mythril) - Security analysis +- [Echidna](https://github.com/crytic/echidna) - Fuzzing tool + +## ๐ŸŒ Community & Forums + +### Discussion +- [Ethereum Stack Exchange](https://ethereum.stackexchange.com/) +- [Reddit r/ethdev](https://reddit.com/r/ethdev) +- [Ethereum Research](https://ethresear.ch/) + +### Discord Servers +- Buildspace +- Developer DAO +- LearnWeb3 +- Alchemy University + +### Twitter +- Follow [@VitalikButerin](https://twitter.com/VitalikButerin) +- [@ethereumproject](https://twitter.com/ethereum) +- [@HardhatHQ](https://twitter.com/HardhatHQ) + +## ๐Ÿ“ฐ News & Updates + +- [Week in Ethereum](https://weekinethereumnews.com/) +- [EthHub](https://ethhub.io/) +- [The Defiant](https://thedefiant.io/) +- [Decrypt](https://decrypt.co/) + +## ๐Ÿ”ง Useful Libraries & Frameworks + +### Smart Contracts +- [OpenZeppelin Contracts](https://openzeppelin.com/contracts/) - Secure implementations +- [Solmate](https://github.com/transmissions11/solmate) - Gas-optimized contracts +- [DSTest](https://github.com/dapphub/ds-test) - Testing framework + +### Frontend +- [Wagmi](https://wagmi.sh/) - React hooks for Ethereum +- [Web3Modal](https://web3modal.com/) - Wallet connection +- [RainbowKit](https://www.rainbowkit.com/) - Wallet UI +- [ethers.js](https://docs.ethers.org/) - Ethereum library +- [web3.js](https://web3js.readthedocs.io/) - Alternative library + +### Backend & Indexing +- [The Graph](https://thegraph.com/) - Indexing protocol +- [Moralis](https://moralis.io/) - Web3 APIs +- [Alchemy](https://www.alchemy.com/) - Node provider & APIs + +## ๐ŸŽฏ Standards & Protocols + +### Token Standards +- [ERC-20](https://eips.ethereum.org/EIPS/eip-20) - Fungible tokens +- [ERC-721](https://eips.ethereum.org/EIPS/eip-721) - NFTs +- [ERC-1155](https://eips.ethereum.org/EIPS/eip-1155) - Multi-token +- [ERC-4626](https://eips.ethereum.org/EIPS/eip-4626) - Tokenized vaults + +### Other Standards +- [EIP-2535](https://eips.ethereum.org/EIPS/eip-2535) - Diamond standard +- [EIP-2981](https://eips.ethereum.org/EIPS/eip-2981) - NFT royalties + +## ๐Ÿ” Security Resources + +- [Smart Contract Security Best Practices](https://consensys.github.io/smart-contract-best-practices/) +- [SWC Registry](https://swcregistry.io/) - Weakness classification +- [Secureum Bootcamp](https://secureum.substack.com/) +- [OpenZeppelin Security Audits](https://blog.openzeppelin.com/security-audits/) + +## ๐Ÿ’ก Project Ideas + +### Beginner +- Simple token (ERC-20) +- Basic NFT collection (ERC-721) +- Voting system +- Todo list on blockchain + +### Intermediate +- Decentralized marketplace +- DAO (Decentralized Autonomous Organization) +- Staking platform +- Lottery/raffle system + +### Advanced +- DEX (Decentralized Exchange) +- Lending protocol +- NFT marketplace with royalties +- Cross-chain bridge + +## ๐ŸŒŸ Inspiration + +### Notable Projects +- [Uniswap](https://uniswap.org/) - DEX +- [Aave](https://aave.com/) - Lending +- [OpenSea](https://opensea.io/) - NFT marketplace +- [ENS](https://ens.domains/) - Name service + +### GitHub Repos to Study +- [Uniswap V2 Core](https://github.com/Uniswap/v2-core) +- [Compound Protocol](https://github.com/compound-finance/compound-protocol) +- [OpenZeppelin Contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) + +## ๐Ÿ“Š Analytics & Data + +- [Etherscan](https://etherscan.io/) - Block explorer +- [Dune Analytics](https://dune.com/) - On-chain analytics +- [DeFi Llama](https://defillama.com/) - DeFi TVL tracker +- [Gas Station](https://ethgasstation.info/) - Gas prices + +## ๐ŸŽช Events & Hackathons + +- [ETHGlobal](https://ethglobal.com/) - Hackathons worldwide +- [Gitcoin Grants](https://gitcoin.co/grants/) - Funding for projects +- [Devcon](https://devcon.org/) - Annual Ethereum conference +- [EthCC](https://ethcc.io/) - European conference + +## ๐Ÿš€ Next Steps After This Project + +1. **Build More**: Create 3-5 different dApps +2. **Contribute**: Contribute to open-source projects +3. **Network**: Join communities and attend events +4. **Specialize**: Choose DeFi, NFTs, DAOs, or another area +5. **Ship**: Deploy a real project to mainnet + +--- + +Remember: The best way to learn is by building! Start small, iterate often, and never stop exploring. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..3bce628 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,122 @@ +# Security Considerations + +## โš ๏ธ Important Security Guidelines + +### Development + +#### Private Keys +- **NEVER** commit `.env` to git +- **NEVER** share your private key +- Use separate wallets for development and production +- Keep only small amounts in development wallets + +#### Testing +- Always test thoroughly before mainnet deployment +- Use testnets (Sepolia, Goerli) for realistic testing +- Run security audits for production contracts +- Test edge cases and failure scenarios + +### Smart Contract Security + +#### Common Vulnerabilities + +1. **Reentrancy** +```solidity +// BAD - Vulnerable to reentrancy +function withdraw() public { + uint amount = balances[msg.sender]; + msg.sender.call{value: amount}(""); + balances[msg.sender] = 0; +} + +// GOOD - Protected +function withdraw() public { + uint amount = balances[msg.sender]; + balances[msg.sender] = 0; // Update state first + msg.sender.call{value: amount}(""); +} +``` + +2. **Integer Overflow/Underflow** +```solidity +// Use Solidity 0.8+ which has built-in overflow checks +// Or use OpenZeppelin's SafeMath for older versions +``` + +3. **Access Control** +```solidity +// GOOD - Proper access control +modifier onlyOwner() { + require(msg.sender == owner, "Not authorized"); + _; +} +``` + +#### Best Practices + +- Use OpenZeppelin contracts (battle-tested) +- Follow Checks-Effects-Interactions pattern +- Implement circuit breakers for emergencies +- Use events for important state changes +- Validate all inputs +- Handle errors explicitly +- Keep contracts simple and modular + +### Frontend Security + +#### User Input Validation +```javascript +// Always validate addresses +if (!ethers.utils.isAddress(address)) { + throw new Error("Invalid address"); +} + +// Validate amounts +if (amount <= 0) { + throw new Error("Amount must be positive"); +} +``` + +#### Transaction Safety +```javascript +// Always show transaction details before sending +console.log("Sending", amount, "to", recipient); + +// Wait for confirmations +const tx = await contract.transfer(recipient, amount); +await tx.wait(2); // Wait for 2 confirmations +``` + +### Deployment Security + +#### Pre-Deployment Checklist +- [ ] All tests passing +- [ ] Code reviewed +- [ ] Security audit completed (for mainnet) +- [ ] Gas optimizations done +- [ ] Documentation complete +- [ ] Emergency procedures documented +- [ ] Upgrade plan in place + +#### Post-Deployment +- Monitor contract activity +- Have emergency response plan +- Document all contract addresses +- Verify contracts on Etherscan +- Set up monitoring and alerts + +### Resources + +- [Smart Contract Security Best Practices](https://consensys.github.io/smart-contract-best-practices/) +- [SWC Registry](https://swcregistry.io/) - Known vulnerabilities +- [OpenZeppelin Security](https://docs.openzeppelin.com/contracts/security) +- [Ethernaut](https://ethernaut.openzeppelin.com/) - Security training + +## Getting Security Audits + +For production contracts: +- [ConsenSys Diligence](https://consensys.net/diligence/) +- [OpenZeppelin](https://openzeppelin.com/security-audits/) +- [Trail of Bits](https://www.trailofbits.com/) + +Remember: Security is ongoing, not a one-time task! diff --git a/contracts/MyToken.sol b/contracts/MyToken.sol new file mode 100644 index 0000000..17781e2 --- /dev/null +++ b/contracts/MyToken.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +/** + * @title MyToken + * @dev A simple ERC20 token implementation + * This demonstrates how to create a basic cryptocurrency token + */ +contract MyToken is ERC20, Ownable { + /** + * @dev Constructor that gives msg.sender all of initial supply + * @param initialSupply The initial token supply (in smallest unit) + */ + constructor(uint256 initialSupply) ERC20("MyToken", "MTK") Ownable(msg.sender) { + _mint(msg.sender, initialSupply); + } + + /** + * @dev Mint new tokens (only owner can call this) + * @param to Address to receive the tokens + * @param amount Amount of tokens to mint + */ + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} diff --git a/contracts/SimpleStorage.sol b/contracts/SimpleStorage.sol new file mode 100644 index 0000000..7632f94 --- /dev/null +++ b/contracts/SimpleStorage.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +/** + * @title SimpleStorage + * @dev A simple smart contract to store and retrieve a value + * This is a great starting point for learning Solidity! + */ +contract SimpleStorage { + // State variable to store a number + uint256 private storedData; + + // Event emitted when the stored value changes + event ValueChanged(uint256 newValue, address changedBy); + + /** + * @dev Store a new value + * @param x The new value to store + */ + function set(uint256 x) public { + storedData = x; + emit ValueChanged(x, msg.sender); + } + + /** + * @dev Retrieve the stored value + * @return The stored value + */ + function get() public view returns (uint256) { + return storedData; + } +} diff --git a/docs/CONTRACTS.md b/docs/CONTRACTS.md new file mode 100644 index 0000000..70d7ec4 --- /dev/null +++ b/docs/CONTRACTS.md @@ -0,0 +1,296 @@ +# Smart Contracts Guide + +This guide explains the smart contracts included in this starter repository. + +## Overview + +This repository includes two example contracts: + +1. **SimpleStorage** - A basic contract to learn Solidity fundamentals +2. **MyToken** - An ERC20 token implementation + +## SimpleStorage Contract + +### Purpose +SimpleStorage is the simplest possible smart contract - it stores a number and lets you retrieve it. Perfect for learning! + +### Code Walkthrough + +```solidity +contract SimpleStorage { + uint256 private storedData; + event ValueChanged(uint256 newValue, address changedBy); + + function set(uint256 x) public { + storedData = x; + emit ValueChanged(x, msg.sender); + } + + function get() public view returns (uint256) { + return storedData; + } +} +``` + +### Key Concepts + +**State Variables** +```solidity +uint256 private storedData; +``` +- Stored permanently on the blockchain +- `uint256` = unsigned integer (0 to 2^256-1) +- `private` = only accessible within this contract + +**Functions** +```solidity +function set(uint256 x) public +``` +- `public` = anyone can call this +- Changes state = costs gas +- Requires a transaction + +```solidity +function get() public view returns (uint256) +``` +- `view` = only reads data, doesn't change state +- Free to call (no gas cost) +- Returns a uint256 value + +**Events** +```solidity +event ValueChanged(uint256 newValue, address changedBy); +emit ValueChanged(x, msg.sender); +``` +- Events log data to the blockchain +- Can be filtered and searched +- `msg.sender` = address calling the function + +### Usage Examples + +```javascript +// Deploy +const SimpleStorage = await ethers.getContractFactory("SimpleStorage"); +const contract = await SimpleStorage.deploy(); + +// Set a value (costs gas) +await contract.set(42); + +// Get the value (free) +const value = await contract.get(); // Returns 42 + +// Listen for events +contract.on("ValueChanged", (newValue, changedBy) => { + console.log(`Value changed to ${newValue} by ${changedBy}`); +}); +``` + +## MyToken Contract (ERC20) + +### Purpose +MyToken demonstrates how to create a cryptocurrency token using the ERC20 standard. + +### Code Walkthrough + +```solidity +contract MyToken is ERC20, Ownable { + constructor(uint256 initialSupply) + ERC20("MyToken", "MTK") + Ownable(msg.sender) + { + _mint(msg.sender, initialSupply); + } + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} +``` + +### Key Concepts + +**Inheritance** +```solidity +contract MyToken is ERC20, Ownable +``` +- Inherits from OpenZeppelin's ERC20 and Ownable +- Gets all standard token functions +- Gets owner management + +**Constructor** +```solidity +constructor(uint256 initialSupply) +``` +- Runs once when contract is deployed +- Sets token name ("MyToken") and symbol ("MTK") +- Mints initial supply to deployer + +**Access Control** +```solidity +function mint(address to, uint256 amount) public onlyOwner +``` +- `onlyOwner` modifier restricts access +- Only contract owner can mint new tokens +- Prevents unauthorized inflation + +### ERC20 Standard Functions + +Your token automatically has these functions: + +```javascript +// Get token balance +await token.balanceOf(address); + +// Transfer tokens +await token.transfer(recipient, amount); + +// Approve someone to spend your tokens +await token.approve(spender, amount); + +// Transfer tokens on behalf of someone +await token.transferFrom(from, to, amount); + +// Get token name and symbol +await token.name(); // "MyToken" +await token.symbol(); // "MTK" + +// Get decimals (default 18) +await token.decimals(); // 18 + +// Get total supply +await token.totalSupply(); +``` + +### Usage Examples + +```javascript +// Deploy with 1 million tokens +const MyToken = await ethers.getContractFactory("MyToken"); +const initialSupply = ethers.parseEther("1000000"); // 1M tokens +const token = await MyToken.deploy(initialSupply); + +// Check your balance +const balance = await token.balanceOf(owner.address); +console.log(ethers.formatEther(balance)); // "1000000.0" + +// Transfer tokens +await token.transfer(recipient, ethers.parseEther("100")); + +// Mint new tokens (only owner) +await token.mint(recipient, ethers.parseEther("1000")); +``` + +## Understanding Wei, Gwei, and Ether + +Ethereum uses different units: + +```javascript +// 1 Ether = 1,000,000,000,000,000,000 Wei (10^18) +ethers.parseEther("1.0") // 1 Ether in Wei +ethers.formatEther(amount) // Wei to Ether + +// Common amounts +ethers.parseEther("0.1") // 0.1 ETH +ethers.parseUnits("50", "gwei") // 50 Gwei +``` + +## Gas and Costs + +Every transaction costs gas: + +```javascript +// Estimate gas for a transaction +const gasEstimate = await contract.set.estimateGas(42); + +// Send with custom gas limit +await contract.set(42, { gasLimit: 100000 }); + +// View functions are free! +const value = await contract.get(); // No gas cost +``` + +## Security Best Practices + +### Input Validation +```solidity +function set(uint256 x) public { + require(x > 0, "Value must be positive"); + storedData = x; +} +``` + +### Access Control +```solidity +mapping(address => bool) public authorized; + +modifier onlyAuthorized() { + require(authorized[msg.sender], "Not authorized"); + _; +} + +function restrictedFunction() public onlyAuthorized { + // Only authorized users can call this +} +``` + +### Reentrancy Protection +```solidity +bool private locked; + +modifier noReentrant() { + require(!locked, "No reentrancy"); + locked = true; + _; + locked = false; +} +``` + +## Modifying the Contracts + +### Add a New Function to SimpleStorage + +```solidity +function increment() public { + storedData += 1; + emit ValueChanged(storedData, msg.sender); +} + +function decrement() public { + require(storedData > 0, "Cannot go below zero"); + storedData -= 1; + emit ValueChanged(storedData, msg.sender); +} +``` + +### Add Token Burning + +```solidity +function burn(uint256 amount) public { + _burn(msg.sender, amount); +} +``` + +## Testing Your Changes + +After modifying contracts: + +1. Update tests in `test/` +2. Run `npm test` +3. Fix any failures +4. Recompile: `npm run compile` +5. Redeploy: `npm run deploy:local` + +## Next Steps + +- Learn about [mappings and arrays](https://docs.soliditylang.org/en/latest/types.html) +- Explore [OpenZeppelin contracts](https://docs.openzeppelin.com/contracts) +- Read about [common vulnerabilities](https://swcregistry.io/) +- Try building a voting contract +- Create an NFT (ERC721) contract + +## Resources + +- [Solidity Documentation](https://docs.soliditylang.org/) +- [OpenZeppelin Learn](https://docs.openzeppelin.com/learn/) +- [Ethernaut (security challenges)](https://ethernaut.openzeppelin.com/) +- [CryptoZombies (interactive tutorial)](https://cryptozombies.io/) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..27f1662 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,211 @@ +# Contributing to First-dApp + +Thank you for your interest in contributing! This document provides guidelines for contributing to this project. + +## Getting Started + +1. Fork the repository +2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/First-dApp.git` +3. Create a branch: `git checkout -b feature/your-feature-name` +4. Make your changes +5. Test your changes +6. Commit your changes +7. Push to your fork +8. Open a Pull Request + +## Development Workflow + +### Before Making Changes + +1. Make sure you're on the latest main branch: + ```bash + git checkout main + git pull origin main + ``` + +2. Install dependencies: + ```bash + npm install + ``` + +3. Run tests to ensure everything works: + ```bash + npm test + ``` + +### Making Changes + +1. Create a new branch: + ```bash + git checkout -b feature/your-feature-name + ``` + +2. Make your changes following our coding standards (see below) + +3. Test your changes: + ```bash + npm test + npm run compile + ``` + +4. Update documentation if needed + +### Committing Changes + +1. Stage your changes: + ```bash + git add . + ``` + +2. Commit with a descriptive message: + ```bash + git commit -m "Add feature: description of your change" + ``` + + Good commit messages: + - "Add function to mint tokens in batches" + - "Fix: Prevent reentrancy in transfer function" + - "Update: Improve gas efficiency in storage contract" + - "Docs: Add tutorial for deploying to testnet" + +3. Push to your fork: + ```bash + git push origin feature/your-feature-name + ``` + +### Opening a Pull Request + +1. Go to the original repository on GitHub +2. Click "New Pull Request" +3. Select your fork and branch +4. Fill in the PR template: + - Describe what you changed + - Explain why you made the change + - List any breaking changes + - Reference related issues + +## Coding Standards + +### Solidity + +Follow the [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html): + +```solidity +// Good +contract MyContract { + uint256 public myVariable; + + event MyEvent(address indexed user, uint256 value); + + function myFunction(uint256 _param) public returns (uint256) { + require(_param > 0, "Parameter must be positive"); + myVariable = _param; + emit MyEvent(msg.sender, _param); + return myVariable; + } +} +``` + +**Naming Conventions:** +- Contracts: PascalCase (e.g., `SimpleStorage`) +- Functions: camelCase (e.g., `getBalance`) +- Parameters: _underscorePrefix (e.g., `_amount`) +- Constants: UPPER_CASE (e.g., `MAX_SUPPLY`) + +**Comments:** +- Use NatSpec for public functions +- Explain complex logic +- Keep comments up to date + +```solidity +/** + * @dev Transfers tokens to a recipient + * @param _recipient Address to receive tokens + * @param _amount Number of tokens to transfer + * @return success Whether transfer succeeded + */ +function transfer(address _recipient, uint256 _amount) + public + returns (bool success) +{ + // Implementation +} +``` + +### JavaScript/Testing + +Follow common JavaScript standards: + +```javascript +// Good +const contract = await SimpleStorage.deploy(); +const value = await contract.get(); +expect(value).to.equal(42); +``` + +**Testing Guidelines:** +- Test one thing per test +- Use descriptive test names +- Test edge cases +- Test error conditions + +## Testing Requirements + +All contributions must include tests: + +### Smart Contracts +- Unit tests for new functions +- Integration tests for complex features +- Test success cases and failures +- Check events are emitted + +## Documentation + +Update documentation when you: +- Add new features +- Change existing behavior +- Add new dependencies +- Modify deployment process + +## What to Contribute + +### Good First Issues +- Fix typos in documentation +- Improve error messages +- Add comments to code +- Write more tests +- Update dependencies + +### Features +- New example contracts +- Frontend improvements +- Additional network support +- Better error handling +- Gas optimizations + +### Bug Fixes +- Security vulnerabilities +- Logic errors +- UI bugs +- Documentation errors + +## Code Review Process + +1. Maintainers will review your PR +2. They may request changes +3. Make requested changes and push +4. Once approved, PR will be merged + +## Code of Conduct + +Be respectful and professional: +- Be welcoming and inclusive +- Respect differing opinions +- Accept constructive criticism +- Focus on what's best for the project + +## License + +By contributing, you agree that your contributions will be licensed under the Apache License 2.0. + +Thank you for contributing! ๐ŸŽ‰ diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..3df00d3 --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,387 @@ +# Deployment Guide + +This guide walks you through deploying your smart contracts to different networks. + +## Networks Overview + +### Local Network (Development) +- **Purpose**: Testing during development +- **Cost**: Free +- **Speed**: Instant +- **Reset**: Restart = fresh blockchain + +### Testnets (Staging) +- **Purpose**: Testing with real blockchain +- **Cost**: Free (use faucets) +- **Speed**: Similar to mainnet +- **Networks**: Sepolia, Goerli + +### Mainnet (Production) +- **Purpose**: Real deployment +- **Cost**: Real ETH +- **Speed**: ~12-15 seconds per block +- **Risk**: Real money involved! + +## Local Deployment + +### 1. Start Local Node + +```bash +npm run node +``` + +Keep this terminal running. + +### 2. Deploy + +In a new terminal: + +```bash +npm run deploy:local +``` + +### 3. Verify + +The script will output contract addresses: +``` +SimpleStorage deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +MyToken deployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 +``` + +These addresses are also saved to `deployment-addresses.json`. + +## Testnet Deployment (Sepolia) + +### Prerequisites + +1. **Get test ETH** + - Go to [sepoliafaucet.com](https://sepoliafaucet.com/) + - Enter your wallet address + - Wait for ETH (usually 0.5 ETH) + +2. **Get RPC URL** + - Sign up at [alchemy.com](https://www.alchemy.com/) + - Create new app (select Sepolia) + - Copy API key + +3. **Configure .env** + +```bash +SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_API_KEY +PRIVATE_KEY=your_private_key_from_metamask +ETHERSCAN_API_KEY=your_etherscan_api_key +``` + +โš ๏ธ **Security Warning**: Use a separate wallet for testing! Never use your main wallet's private key. + +### Deploy to Sepolia + +```bash +npm run deploy:testnet +``` + +Wait for transactions to confirm (may take 30-60 seconds). + +### Verify on Etherscan + +After deployment, verify your contracts: + +1. Go to [sepolia.etherscan.io](https://sepolia.etherscan.io/) +2. Search for your contract address +3. Go to "Contract" tab +4. Click "Verify and Publish" +5. Or use Hardhat: + +```bash +npx hardhat verify --network sepolia CONTRACT_ADDRESS "constructor_args" +``` + +Example: +```bash +npx hardhat verify --network sepolia 0x123... 1000000000000000000000000 +``` + +## Mainnet Deployment + +โš ๏ธ **WARNING**: Mainnet uses real ETH! Double-check everything! + +### Pre-Deployment Checklist + +- [ ] Contracts thoroughly tested +- [ ] Security audit completed +- [ ] All tests passing +- [ ] Gas optimization done +- [ ] Error messages clear +- [ ] Access controls verified +- [ ] Emergency pause mechanism (if needed) +- [ ] Upgrade path considered + +### Steps + +1. **Add Mainnet Config** to `hardhat.config.js`: + +```javascript +mainnet: { + url: process.env.MAINNET_RPC_URL || "", + accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [], + chainId: 1 +} +``` + +2. **Update .env**: + +```bash +MAINNET_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY +PRIVATE_KEY=your_private_key +``` + +3. **Check Gas Prices**: + +Visit [etherscan.io/gastracker](https://etherscan.io/gastracker) to check current gas prices. Deploy during low gas times to save money. + +4. **Deploy**: + +```bash +npx hardhat run scripts/deploy.js --network mainnet +``` + +5. **Verify**: + +```bash +npx hardhat verify --network mainnet CONTRACT_ADDRESS "args" +``` + +## Advanced Deployment + +### Custom Deployment Script + +Create `scripts/deploy-custom.js`: + +```javascript +const hre = require("hardhat"); + +async function main() { + console.log("Deploying contracts..."); + + // Get deployer account + const [deployer] = await hre.ethers.getSigners(); + console.log("Deploying with:", deployer.address); + + // Check balance + const balance = await deployer.getBalance(); + console.log("Balance:", hre.ethers.formatEther(balance), "ETH"); + + // Deploy with custom gas + const Contract = await hre.ethers.getContractFactory("MyContract"); + const contract = await Contract.deploy({ + gasLimit: 3000000, + gasPrice: hre.ethers.parseUnits("20", "gwei") + }); + + await contract.waitForDeployment(); + console.log("Deployed to:", await contract.getAddress()); + + // Wait for block confirmations + await contract.deploymentTransaction().wait(5); + console.log("Confirmed!"); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); +``` + +### Deploy with Constructor Arguments + +```javascript +const MyToken = await ethers.getContractFactory("MyToken"); +const initialSupply = ethers.parseEther("1000000"); +const token = await MyToken.deploy(initialSupply); +``` + +### Deploy Multiple Contracts + +```javascript +// Deploy in sequence +const storage = await SimpleStorage.deploy(); +await storage.waitForDeployment(); + +const token = await MyToken.deploy(1000000); +await token.waitForDeployment(); + +// Link contracts if needed +await storage.setTokenAddress(await token.getAddress()); +``` + +## Gas Optimization + +### Estimate Deployment Cost + +```javascript +const Contract = await ethers.getContractFactory("MyContract"); +const deployTx = await Contract.getDeployTransaction(); +const gasEstimate = await provider.estimateGas(deployTx); +console.log("Estimated gas:", gasEstimate.toString()); +``` + +### Set Custom Gas Price + +```javascript +const contract = await Contract.deploy({ + gasPrice: ethers.parseUnits("20", "gwei") +}); +``` + +### Check Current Gas Price + +```javascript +const gasPrice = await provider.getGasPrice(); +console.log("Current gas price:", ethers.formatUnits(gasPrice, "gwei"), "gwei"); +``` + +## Multi-Network Deployment + +Deploy to multiple networks: + +```bash +# Deploy to all testnets +for network in sepolia goerli +do + echo "Deploying to $network..." + npx hardhat run scripts/deploy.js --network $network +done +``` + +## Upgradeable Contracts + +For contracts that need upgrading: + +### Install Plugin + +```bash +npm install @openzeppelin/hardhat-upgrades +``` + +### Deploy Proxy + +```javascript +const { upgrades } = require("hardhat"); + +async function main() { + const Contract = await ethers.getContractFactory("MyContract"); + const proxy = await upgrades.deployProxy(Contract, [arg1, arg2]); + await proxy.waitForDeployment(); + console.log("Proxy deployed to:", await proxy.getAddress()); +} +``` + +### Upgrade Contract + +```javascript +const ContractV2 = await ethers.getContractFactory("MyContractV2"); +const upgraded = await upgrades.upgradeProxy(proxyAddress, ContractV2); +``` + +## Post-Deployment + +### Save Contract Info + +```javascript +const fs = require("fs"); + +const deployment = { + network: hre.network.name, + contracts: { + SimpleStorage: await simpleStorage.getAddress(), + MyToken: await myToken.getAddress() + }, + deployer: deployer.address, + timestamp: new Date().toISOString(), + blockNumber: await provider.getBlockNumber() +}; + +fs.writeFileSync( + `deployments/${hre.network.name}.json`, + JSON.stringify(deployment, null, 2) +); +``` + +### Update Frontend + +After deployment, update `frontend/js/app.js`: + +```javascript +const SIMPLE_STORAGE_ADDRESS = "0xYourDeployedAddress"; +const MY_TOKEN_ADDRESS = "0xYourTokenAddress"; +``` + +### Test Deployed Contracts + +```bash +npx hardhat console --network sepolia +``` + +Then in console: +```javascript +const contract = await ethers.getContractAt( + "SimpleStorage", + "0xYourAddress" +); +await contract.get(); +``` + +## Troubleshooting + +### "Insufficient Funds" +- Check wallet balance +- Make sure you have enough for gas + +### "Nonce Too Low" +- Clear pending transactions in MetaMask +- Or set nonce manually in deployment + +### "Gas Estimation Failed" +- Constructor might be reverting +- Check constructor logic +- Verify arguments are correct + +### "Network Timeout" +- Try different RPC provider +- Increase timeout in hardhat.config.js: + +```javascript +networks: { + sepolia: { + url: "...", + timeout: 60000 // 60 seconds + } +} +``` + +## Best Practices + +1. **Test Extensively**: Always test on testnet first +2. **Use Multi-Sig**: For mainnet, use multi-signature wallet +3. **Verify Contracts**: Always verify on Etherscan +4. **Document Addresses**: Keep record of all deployments +5. **Monitor Contracts**: Set up monitoring after deployment +6. **Plan Upgrades**: Consider upgrade mechanism from start +7. **Backup Data**: Save all deployment info + +## Cost Estimates (Approximate) + +Based on 30 gwei gas price: + +| Contract | Gas Used | Cost (ETH) | Cost (USD @ $2000/ETH) | +|----------|----------|------------|------------------------| +| SimpleStorage | ~150K | 0.0045 | $9 | +| MyToken (ERC20) | ~1.5M | 0.045 | $90 | + +Actual costs vary with gas prices and ETH price. + +## Resources + +- [Etherscan Gas Tracker](https://etherscan.io/gastracker) +- [Hardhat Deploy Plugin](https://github.com/wighawag/hardhat-deploy) +- [OpenZeppelin Upgrades](https://docs.openzeppelin.com/upgrades-plugins/1.x/) diff --git a/docs/FRONTEND.md b/docs/FRONTEND.md new file mode 100644 index 0000000..c0855e7 --- /dev/null +++ b/docs/FRONTEND.md @@ -0,0 +1,418 @@ +# Frontend Guide + +This guide explains how the frontend works and how to customize it. + +## Overview + +The frontend is a simple web interface that connects to your smart contracts using: +- **HTML** - Structure +- **CSS** - Styling +- **JavaScript** - Logic +- **Ethers.js** - Blockchain interaction +- **MetaMask** - Wallet connection + +## File Structure + +``` +frontend/ +โ”œโ”€โ”€ index.html # Main HTML page +โ”œโ”€โ”€ css/ +โ”‚ โ””โ”€โ”€ style.css # Styles +โ””โ”€โ”€ js/ + โ””โ”€โ”€ app.js # Application logic +``` + +## How It Works + +### 1. Wallet Connection + +When users click "Connect Wallet": + +```javascript +await window.ethereum.request({ method: 'eth_requestAccounts' }); +provider = new ethers.providers.Web3Provider(window.ethereum); +signer = provider.getSigner(); +``` + +This: +- Requests MetaMask permission +- Creates a provider to read blockchain data +- Creates a signer to send transactions + +### 2. Contract Interaction + +Contracts are initialized with address and ABI: + +```javascript +const contract = new ethers.Contract( + contractAddress, + contractABI, + signer +); +``` + +**Reading data** (free, no gas): +```javascript +const value = await contract.get(); +``` + +**Writing data** (costs gas): +```javascript +const tx = await contract.set(42); +await tx.wait(); // Wait for confirmation +``` + +### 3. Handling Events + +Listen for contract events: + +```javascript +contract.on("ValueChanged", (newValue, changedBy) => { + console.log(`Value: ${newValue} changed by ${changedBy}`); +}); +``` + +## Key Components + +### MetaMask Detection + +```javascript +if (typeof window.ethereum === 'undefined') { + alert('Please install MetaMask!'); +} +``` + +### Network Detection + +```javascript +const network = await provider.getNetwork(); +console.log(network.name); // "localhost", "sepolia", etc. +``` + +### Account Changes + +```javascript +window.ethereum.on('accountsChanged', (accounts) => { + if (accounts.length === 0) { + // User disconnected + } else { + // Account changed + location.reload(); + } +}); +``` + +### Transaction Status + +```javascript +// Send transaction +const tx = await contract.set(42); +console.log("Transaction hash:", tx.hash); + +// Wait for confirmation +const receipt = await tx.wait(); +console.log("Confirmed in block:", receipt.blockNumber); +``` + +## Customizing the Frontend + +### Change Styling + +Edit `css/style.css`: + +```css +/* Change primary color */ +.btn-primary { + background: linear-gradient(135deg, #your-color1, #your-color2); +} + +/* Modify card appearance */ +.card { + background: #your-background; + border-radius: 20px; +} +``` + +### Add New Contract Functions + +1. **Add ABI entry** in `app.js`: +```javascript +const CONTRACT_ABI = [ + "function yourNewFunction(uint256 x) public", + // ... other functions +]; +``` + +2. **Add HTML element** in `index.html`: +```html +
+ + +
+``` + +3. **Add event listener** in `app.js`: +```javascript +document.getElementById('newBtn').addEventListener('click', yourNewFunction); +``` + +4. **Implement function**: +```javascript +async function yourNewFunction() { + try { + const value = document.getElementById('newInput').value; + const tx = await contract.yourNewFunction(value); + await tx.wait(); + showStatus('Success!', 'success'); + } catch (error) { + showStatus('Error: ' + error.message, 'error'); + } +} +``` + +### Display Token Balances + +```javascript +async function displayBalance() { + const balance = await tokenContract.balanceOf(userAccount); + const symbol = await tokenContract.symbol(); + + // Convert from Wei to Ether + const formatted = ethers.utils.formatEther(balance); + + document.getElementById('balance').textContent = + `${formatted} ${symbol}`; +} +``` + +### Format Addresses + +```javascript +function formatAddress(address) { + return address.slice(0, 6) + '...' + address.slice(-4); +} + +// Display: 0x1234...5678 +``` + +## Error Handling + +### Common Errors + +**User Rejected Transaction** +```javascript +try { + await contract.transfer(recipient, amount); +} catch (error) { + if (error.code === 4001) { + showStatus('Transaction cancelled', 'info'); + } +} +``` + +**Insufficient Funds** +```javascript +catch (error) { + if (error.code === 'INSUFFICIENT_FUNDS') { + showStatus('Not enough ETH for gas', 'error'); + } +} +``` + +**Wrong Network** +```javascript +const network = await provider.getNetwork(); +if (network.chainId !== 1337) { + showStatus('Please switch to localhost network', 'error'); +} +``` + +## Best Practices + +### 1. Always Validate Input + +```javascript +if (!ethers.utils.isAddress(address)) { + showStatus('Invalid address', 'error'); + return; +} + +if (amount <= 0) { + showStatus('Amount must be positive', 'error'); + return; +} +``` + +### 2. Handle Loading States + +```javascript +async function setStorageValue() { + const btn = document.getElementById('setValueBtn'); + btn.disabled = true; + btn.textContent = 'Processing...'; + + try { + await contract.set(value); + } finally { + btn.disabled = false; + btn.textContent = 'Store Value'; + } +} +``` + +### 3. Use Try-Catch + +```javascript +async function callContract() { + try { + const result = await contract.someFunction(); + showStatus('Success!', 'success'); + } catch (error) { + console.error(error); + showStatus('Error: ' + error.message, 'error'); + } +} +``` + +### 4. Clear Sensitive Data + +```javascript +// After successful transfer +document.getElementById('recipientInput').value = ''; +document.getElementById('amountInput').value = ''; +``` + +## Advanced Features + +### Listen to All Events + +```javascript +contract.on('*', (event) => { + console.log('Event:', event); +}); +``` + +### Get Transaction Receipt + +```javascript +const receipt = await tx.wait(); +console.log('Gas used:', receipt.gasUsed.toString()); +console.log('Block number:', receipt.blockNumber); +``` + +### Estimate Gas Before Sending + +```javascript +const gasEstimate = await contract.estimateGas.transfer( + recipient, + amount +); +console.log('Estimated gas:', gasEstimate.toString()); +``` + +### Read Past Events + +```javascript +const filter = contract.filters.ValueChanged(); +const events = await contract.queryFilter(filter, 0, 'latest'); +events.forEach(event => { + console.log('Value:', event.args.newValue); +}); +``` + +## Testing the Frontend + +### Manual Testing Checklist + +- [ ] Wallet connects successfully +- [ ] Correct network displayed +- [ ] Contract calls work +- [ ] Transactions confirm +- [ ] Events are caught +- [ ] Errors display properly +- [ ] UI updates correctly +- [ ] Works on mobile + +### Browser Console + +Open DevTools (F12) to: +- See console.log messages +- Debug JavaScript errors +- Monitor network requests +- Inspect contract calls + +## Deployment + +### Serve Locally + +```bash +# Using Python +python3 -m http.server 8000 + +# Using Node.js +npx http-server +``` + +Then open `http://localhost:8000` + +### Deploy to GitHub Pages + +1. Push frontend to `gh-pages` branch +2. Enable GitHub Pages in settings +3. Your dApp will be at `https://username.github.io/repo` + +### Deploy to IPFS + +```bash +# Install IPFS +npm install -g ipfs + +# Add frontend +ipfs add -r frontend/ + +# Pin to Pinata or other service +``` + +## Troubleshooting + +### MetaMask Not Detected +- Make sure extension is installed +- Try refreshing the page +- Check browser console for errors + +### Transactions Failing +- Check gas settings in MetaMask +- Verify contract address is correct +- Ensure sufficient ETH balance +- Check network is correct + +### Wrong Network +```javascript +// Add network switching +async function switchNetwork(chainId) { + try { + await window.ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: `0x${chainId.toString(16)}` }], + }); + } catch (error) { + // Handle error + } +} +``` + +## Next Steps + +- Add wallet balance display +- Implement transaction history +- Add loading animations +- Create responsive mobile design +- Add dark mode toggle +- Integrate with The Graph for queries +- Add ENS name resolution + +## Resources + +- [Ethers.js Docs](https://docs.ethers.org/) +- [MetaMask Docs](https://docs.metamask.io/) +- [Web3 Design Patterns](https://www.web3designpatterns.com/) diff --git a/docs/SETUP.md b/docs/SETUP.md new file mode 100644 index 0000000..bfb3176 --- /dev/null +++ b/docs/SETUP.md @@ -0,0 +1,212 @@ +# Setup Guide + +This guide will walk you through setting up your development environment for building dApps. + +## Prerequisites + +### 1. Install Node.js + +Download and install Node.js from [nodejs.org](https://nodejs.org/). We recommend the LTS version (v16 or later). + +Verify installation: +```bash +node --version +npm --version +``` + +### 2. Install MetaMask + +MetaMask is a browser wallet that lets you interact with Ethereum: + +1. Visit [metamask.io](https://metamask.io/) +2. Install the browser extension +3. Create a new wallet (save your seed phrase securely!) +4. Get some test ETH from a faucet + +### 3. Get Test ETH + +For testnets, you'll need test ETH: +- Sepolia Faucet: [sepoliafaucet.com](https://sepoliafaucet.com/) +- Goerli Faucet: [goerlifaucet.com](https://goerlifaucet.com/) + +## Project Setup + +### 1. Clone and Install + +```bash +# Navigate to project directory +cd First-dApp + +# Install dependencies +npm install +``` + +This will install: +- Hardhat (development environment) +- Ethers.js (library for blockchain interaction) +- OpenZeppelin (secure contract libraries) +- Testing utilities + +### 2. Configure Environment + +Create your environment file: +```bash +cp .env.example .env +``` + +Edit `.env` and add your values: +``` +SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY +PRIVATE_KEY=your_metamask_private_key_here +ETHERSCAN_API_KEY=your_etherscan_api_key +``` + +**Important Security Notes:** +- Never commit your `.env` file to git +- Never share your private key +- Use a separate wallet for development +- Keep only small amounts in test wallets + +### 3. Get RPC URL (Optional - for testnets) + +For testnet deployment, you'll need an RPC URL: + +1. Go to [Alchemy](https://www.alchemy.com/) or [Infura](https://infura.io/) +2. Create a free account +3. Create a new app +4. Copy your API key +5. Add it to `.env` + +### 4. Compile Contracts + +```bash +npm run compile +``` + +This compiles your Solidity contracts and generates: +- Contract artifacts in `artifacts/` +- TypeScript types in `typechain/` (if using TypeScript) + +### 5. Run Tests + +```bash +npm test +``` + +You should see all tests passing! โœ… + +## Local Development + +### Start Local Blockchain + +Hardhat provides a local Ethereum network: + +```bash +npm run node +``` + +This starts a local blockchain at `http://127.0.0.1:8545` with: +- 20 test accounts with 10,000 ETH each +- Automatic mining +- Console output of all transactions + +**Keep this terminal running!** + +### Deploy to Local Network + +In a new terminal: + +```bash +npm run deploy:local +``` + +This will: +1. Deploy all contracts +2. Display contract addresses +3. Save addresses to `deployment-addresses.json` + +### Connect MetaMask to Local Network + +1. Open MetaMask +2. Click network dropdown +3. Select "Add Network" โ†’ "Add a network manually" +4. Enter these details: + - Network Name: Localhost 8545 + - RPC URL: http://127.0.0.1:8545 + - Chain ID: 1337 + - Currency Symbol: ETH +5. Click "Save" + +### Import Test Account + +To use a test account from Hardhat: + +1. Copy a private key from the Hardhat console +2. In MetaMask: Click account icon โ†’ Import Account +3. Paste the private key +4. You'll now have 10,000 test ETH! + +## Using the Frontend + +1. After deploying contracts, the deployment script creates `deployment-addresses.json` +2. Update `frontend/js/app.js` with contract addresses (or the app will load them automatically) +3. Open `frontend/index.html` in your browser +4. Connect MetaMask +5. Interact with your contracts! + +## Troubleshooting + +### "Cannot find module" +```bash +rm -rf node_modules package-lock.json +npm install +``` + +### "Transaction failed" +- Make sure MetaMask is on the correct network +- Check you have enough ETH for gas +- Look at the error message in MetaMask + +### "Contract not deployed" +- Run the deployment script +- Check you're on the right network +- Verify contract addresses in the frontend + +### "Network timeout" +- Check your RPC URL +- Try a different RPC provider +- For local network, make sure Hardhat node is running + +## Next Steps + +Now that you're set up: +1. Read [CONTRACTS.md](./CONTRACTS.md) to understand the smart contracts +2. Check [FRONTEND.md](./FRONTEND.md) to learn about the UI +3. Try modifying the contracts and redeploying +4. Build your own features! + +## Additional Tools + +Consider installing these helpful tools: + +### Hardhat VSCode Extension +- Syntax highlighting for Solidity +- Code completion +- Inline error checking + +### Solidity VSCode Extension +- Advanced Solidity support +- Code formatting +- Security linting + +### Remix IDE +- Browser-based Solidity IDE +- Great for quick testing +- Visit [remix.ethereum.org](https://remix.ethereum.org/) + +## Getting Help + +- Check the [main README](../README.md) +- Read Hardhat docs: [hardhat.org/docs](https://hardhat.org/docs) +- Ask on Stack Overflow with the `ethereum` tag +- Join Ethereum developer Discord communities diff --git a/frontend/css/style.css b/frontend/css/style.css new file mode 100644 index 0000000..6f455a6 --- /dev/null +++ b/frontend/css/style.css @@ -0,0 +1,189 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; + padding: 20px; + color: #333; +} + +.container { + max-width: 800px; + margin: 0 auto; + background: white; + border-radius: 20px; + padding: 40px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); +} + +header { + text-align: center; + margin-bottom: 40px; +} + +h1 { + color: #667eea; + font-size: 2.5em; + margin-bottom: 10px; +} + +.subtitle { + color: #666; + font-size: 1.1em; +} + +h2 { + color: #764ba2; + margin-top: 30px; + margin-bottom: 20px; + font-size: 1.5em; +} + +.wallet-section { + text-align: center; + margin-bottom: 30px; + padding-bottom: 30px; + border-bottom: 2px solid #f0f0f0; +} + +.wallet-info { + margin-top: 20px; + padding: 15px; + background: #f8f9fa; + border-radius: 10px; +} + +.wallet-info p { + margin: 5px 0; + font-size: 0.9em; +} + +.card { + background: #f8f9fa; + padding: 25px; + border-radius: 15px; + margin-bottom: 20px; +} + +.form-group { + margin-bottom: 20px; +} + +label { + display: block; + margin-bottom: 8px; + color: #555; + font-weight: 600; +} + +input[type="text"], +input[type="number"] { + width: 100%; + padding: 12px; + border: 2px solid #e0e0e0; + border-radius: 8px; + font-size: 1em; + margin-bottom: 10px; + transition: border-color 0.3s; +} + +input[type="text"]:focus, +input[type="number"]:focus { + outline: none; + border-color: #667eea; +} + +.btn { + padding: 12px 30px; + border: none; + border-radius: 8px; + font-size: 1em; + font-weight: 600; + cursor: pointer; + transition: all 0.3s; +} + +.btn-primary { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + font-size: 1.1em; + padding: 15px 40px; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4); +} + +.btn-secondary { + background: #667eea; + color: white; +} + +.btn-secondary:hover { + background: #5568d3; + transform: translateY(-1px); +} + +.btn:disabled { + background: #ccc; + cursor: not-allowed; + transform: none; +} + +.result { + margin-top: 15px; + padding: 15px; + background: white; + border-radius: 8px; + font-weight: 600; + color: #667eea; + min-height: 20px; +} + +.status-section { + margin-top: 30px; + text-align: center; +} + +.status { + padding: 15px; + border-radius: 8px; + font-weight: 500; + min-height: 20px; +} + +.status.success { + background: #d4edda; + color: #155724; +} + +.status.error { + background: #f8d7da; + color: #721c24; +} + +.status.info { + background: #d1ecf1; + color: #0c5460; +} + +@media (max-width: 600px) { + .container { + padding: 20px; + } + + h1 { + font-size: 2em; + } + + .btn-primary { + padding: 12px 25px; + font-size: 1em; + } +} diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..379d715 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,62 @@ + + + + + + My First dApp + + + +
+
+

๐Ÿš€ My First dApp

+

A simple decentralized application to get you started

+
+ +
+ + +
+ +
+

Simple Storage Contract

+
+
+ + + +
+
+ +

+
+
+ +

Token Contract

+
+
+ +

+
+
+ + + + + +
+
+
+ +
+

+
+
+ + + + + diff --git a/frontend/js/app.js b/frontend/js/app.js new file mode 100644 index 0000000..10e4f07 --- /dev/null +++ b/frontend/js/app.js @@ -0,0 +1,221 @@ +// Contract addresses - Update these after deployment +const SIMPLE_STORAGE_ADDRESS = "YOUR_SIMPLE_STORAGE_CONTRACT_ADDRESS"; +const MY_TOKEN_ADDRESS = "YOUR_MY_TOKEN_CONTRACT_ADDRESS"; + +// Contract ABIs (simplified for demo) +const SIMPLE_STORAGE_ABI = [ + "function set(uint256 x) public", + "function get() public view returns (uint256)", + "event ValueChanged(uint256 newValue, address changedBy)" +]; + +const MY_TOKEN_ABI = [ + "function balanceOf(address account) public view returns (uint256)", + "function transfer(address to, uint256 amount) public returns (bool)", + "function name() public view returns (string)", + "function symbol() public view returns (string)", + "function decimals() public view returns (uint8)" +]; + +// Global variables +let provider; +let signer; +let simpleStorageContract; +let myTokenContract; +let userAccount; + +// Initialize the app +async function init() { + setupEventListeners(); + await loadDeploymentAddresses(); +} + +// Load deployment addresses from file +async function loadDeploymentAddresses() { + try { + const response = await fetch('../deployment-addresses.json'); + const data = await response.json(); + if (data.SimpleStorage && data.MyToken) { + SIMPLE_STORAGE_ADDRESS = data.SimpleStorage; + MY_TOKEN_ADDRESS = data.MyToken; + console.log("Loaded deployment addresses:", data); + } + } catch (error) { + console.log("No deployment addresses file found. Please deploy contracts first."); + } +} + +// Setup event listeners +function setupEventListeners() { + document.getElementById('connectWallet').addEventListener('click', connectWallet); + document.getElementById('setValueBtn').addEventListener('click', setStorageValue); + document.getElementById('getValueBtn').addEventListener('click', getStorageValue); + document.getElementById('getBalanceBtn').addEventListener('click', getTokenBalance); + document.getElementById('transferBtn').addEventListener('click', transferTokens); +} + +// Connect to MetaMask +async function connectWallet() { + try { + if (typeof window.ethereum === 'undefined') { + showStatus('Please install MetaMask!', 'error'); + return; + } + + // Request account access + await window.ethereum.request({ method: 'eth_requestAccounts' }); + + // Create provider and signer + provider = new ethers.providers.Web3Provider(window.ethereum); + signer = provider.getSigner(); + userAccount = await signer.getAddress(); + + // Get network + const network = await provider.getNetwork(); + + // Initialize contracts + simpleStorageContract = new ethers.Contract( + SIMPLE_STORAGE_ADDRESS, + SIMPLE_STORAGE_ABI, + signer + ); + + myTokenContract = new ethers.Contract( + MY_TOKEN_ADDRESS, + MY_TOKEN_ABI, + signer + ); + + // Update UI + document.getElementById('connectWallet').style.display = 'none'; + document.getElementById('walletInfo').style.display = 'block'; + document.getElementById('accountAddress').textContent = + userAccount.slice(0, 6) + '...' + userAccount.slice(-4); + document.getElementById('networkName').textContent = network.name; + + showStatus('Wallet connected successfully!', 'success'); + + // Listen for account changes + window.ethereum.on('accountsChanged', handleAccountsChanged); + window.ethereum.on('chainChanged', handleChainChanged); + + } catch (error) { + console.error('Error connecting wallet:', error); + showStatus('Error connecting wallet: ' + error.message, 'error'); + } +} + +// Set storage value +async function setStorageValue() { + try { + const value = document.getElementById('storageValue').value; + if (!value) { + showStatus('Please enter a value', 'error'); + return; + } + + showStatus('Setting value... Please confirm transaction', 'info'); + const tx = await simpleStorageContract.set(value); + showStatus('Transaction sent. Waiting for confirmation...', 'info'); + await tx.wait(); + showStatus('Value stored successfully!', 'success'); + + } catch (error) { + console.error('Error setting value:', error); + showStatus('Error: ' + error.message, 'error'); + } +} + +// Get storage value +async function getStorageValue() { + try { + showStatus('Retrieving value...', 'info'); + const value = await simpleStorageContract.get(); + document.getElementById('storedValue').textContent = + 'Stored Value: ' + value.toString(); + showStatus('Value retrieved successfully!', 'success'); + + } catch (error) { + console.error('Error getting value:', error); + showStatus('Error: ' + error.message, 'error'); + } +} + +// Get token balance +async function getTokenBalance() { + try { + showStatus('Retrieving balance...', 'info'); + const balance = await myTokenContract.balanceOf(userAccount); + const symbol = await myTokenContract.symbol(); + document.getElementById('tokenBalance').textContent = + 'Your Balance: ' + ethers.utils.formatEther(balance) + ' ' + symbol; + showStatus('Balance retrieved successfully!', 'success'); + + } catch (error) { + console.error('Error getting balance:', error); + showStatus('Error: ' + error.message, 'error'); + } +} + +// Transfer tokens +async function transferTokens() { + try { + const recipient = document.getElementById('transferAddress').value; + const amount = document.getElementById('transferAmount').value; + + if (!recipient || !amount) { + showStatus('Please enter recipient address and amount', 'error'); + return; + } + + showStatus('Transferring tokens... Please confirm transaction', 'info'); + const tx = await myTokenContract.transfer( + recipient, + ethers.utils.parseEther(amount) + ); + showStatus('Transaction sent. Waiting for confirmation...', 'info'); + await tx.wait(); + showStatus('Tokens transferred successfully!', 'success'); + + // Clear inputs + document.getElementById('transferAddress').value = ''; + document.getElementById('transferAmount').value = ''; + + } catch (error) { + console.error('Error transferring tokens:', error); + showStatus('Error: ' + error.message, 'error'); + } +} + +// Handle account changes +function handleAccountsChanged(accounts) { + if (accounts.length === 0) { + showStatus('Please connect to MetaMask', 'error'); + location.reload(); + } else { + location.reload(); + } +} + +// Handle chain changes +function handleChainChanged() { + location.reload(); +} + +// Show status message +function showStatus(message, type) { + const statusElement = document.getElementById('statusMessage'); + statusElement.textContent = message; + statusElement.className = 'status ' + type; + + // Auto-clear after 5 seconds for success messages + if (type === 'success') { + setTimeout(() => { + statusElement.textContent = ''; + statusElement.className = 'status'; + }, 5000); + } +} + +// Initialize app when page loads +window.addEventListener('load', init); diff --git a/hardhat.config.js b/hardhat.config.js new file mode 100644 index 0000000..d404532 --- /dev/null +++ b/hardhat.config.js @@ -0,0 +1,34 @@ +require("@nomicfoundation/hardhat-toolbox"); +require("dotenv").config(); + +/** @type import('hardhat/config').HardhatUserConfig */ +module.exports = { + solidity: { + version: "0.8.20", + settings: { + optimizer: { + enabled: true, + runs: 200 + } + } + }, + networks: { + hardhat: { + chainId: 1337 + }, + localhost: { + url: "http://127.0.0.1:8545" + }, + sepolia: { + url: process.env.SEPOLIA_RPC_URL || "", + accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [], + chainId: 11155111 + } + }, + paths: { + sources: "./contracts", + tests: "./test", + cache: "./cache", + artifacts: "./artifacts" + } +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..39c1f3b --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "first-dapp", + "version": "1.0.0", + "description": "A starter template for building your first decentralized application (dApp)", + "main": "index.js", + "scripts": { + "compile": "hardhat compile", + "test": "hardhat test", + "deploy:local": "hardhat run scripts/deploy.js --network localhost", + "deploy:testnet": "hardhat run scripts/deploy.js --network sepolia", + "node": "hardhat node", + "clean": "hardhat clean" + }, + "keywords": [ + "ethereum", + "blockchain", + "dapp", + "smart-contracts", + "hardhat", + "solidity" + ], + "author": "", + "license": "Apache-2.0", + "devDependencies": { + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "hardhat": "^2.19.0" + }, + "dependencies": { + "@openzeppelin/contracts": "^5.0.0", + "dotenv": "^16.3.1" + } +} diff --git a/scripts/deploy.js b/scripts/deploy.js new file mode 100644 index 0000000..c1e131f --- /dev/null +++ b/scripts/deploy.js @@ -0,0 +1,53 @@ +const hre = require("hardhat"); + +async function main() { + console.log("Starting deployment..."); + + // Deploy SimpleStorage + console.log("\nDeploying SimpleStorage..."); + const SimpleStorage = await hre.ethers.getContractFactory("SimpleStorage"); + const simpleStorage = await SimpleStorage.deploy(); + await simpleStorage.waitForDeployment(); + const simpleStorageAddress = await simpleStorage.getAddress(); + console.log("SimpleStorage deployed to:", simpleStorageAddress); + + // Deploy MyToken + console.log("\nDeploying MyToken..."); + const initialSupply = hre.ethers.parseEther("1000000"); // 1 million tokens + const MyToken = await hre.ethers.getContractFactory("MyToken"); + const myToken = await MyToken.deploy(initialSupply); + await myToken.waitForDeployment(); + const myTokenAddress = await myToken.getAddress(); + console.log("MyToken deployed to:", myTokenAddress); + + // Display deployment summary + console.log("\n========================================"); + console.log("Deployment Summary:"); + console.log("========================================"); + console.log("SimpleStorage:", simpleStorageAddress); + console.log("MyToken:", myTokenAddress); + console.log("Initial Token Supply:", hre.ethers.formatEther(initialSupply), "MTK"); + console.log("========================================\n"); + + // Save deployment addresses to a file for frontend use + const fs = require("fs"); + const deploymentInfo = { + network: hre.network.name, + SimpleStorage: simpleStorageAddress, + MyToken: myTokenAddress, + timestamp: new Date().toISOString() + }; + + fs.writeFileSync( + "deployment-addresses.json", + JSON.stringify(deploymentInfo, null, 2) + ); + console.log("Deployment addresses saved to deployment-addresses.json"); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/test/MyToken.test.js b/test/MyToken.test.js new file mode 100644 index 0000000..99b974e --- /dev/null +++ b/test/MyToken.test.js @@ -0,0 +1,63 @@ +const { expect } = require("chai"); +const { ethers } = require("hardhat"); + +describe("MyToken", function () { + let myToken; + let owner; + let addr1; + let addr2; + const INITIAL_SUPPLY = ethers.parseEther("1000000"); + + beforeEach(async function () { + [owner, addr1, addr2] = await ethers.getSigners(); + const MyToken = await ethers.getContractFactory("MyToken"); + myToken = await MyToken.deploy(INITIAL_SUPPLY); + }); + + describe("Deployment", function () { + it("Should set the right owner", async function () { + expect(await myToken.owner()).to.equal(owner.address); + }); + + it("Should assign the total supply to the owner", async function () { + const ownerBalance = await myToken.balanceOf(owner.address); + expect(await myToken.totalSupply()).to.equal(ownerBalance); + }); + + it("Should have correct name and symbol", async function () { + expect(await myToken.name()).to.equal("MyToken"); + expect(await myToken.symbol()).to.equal("MTK"); + }); + }); + + describe("Transactions", function () { + it("Should transfer tokens between accounts", async function () { + const transferAmount = ethers.parseEther("50"); + await myToken.transfer(addr1.address, transferAmount); + expect(await myToken.balanceOf(addr1.address)).to.equal(transferAmount); + }); + + it("Should fail if sender doesn't have enough tokens", async function () { + const initialOwnerBalance = await myToken.balanceOf(owner.address); + await expect( + myToken.connect(addr1).transfer(owner.address, 1) + ).to.be.reverted; + expect(await myToken.balanceOf(owner.address)).to.equal(initialOwnerBalance); + }); + }); + + describe("Minting", function () { + it("Should allow owner to mint new tokens", async function () { + const mintAmount = ethers.parseEther("1000"); + await myToken.mint(addr1.address, mintAmount); + expect(await myToken.balanceOf(addr1.address)).to.equal(mintAmount); + }); + + it("Should not allow non-owner to mint", async function () { + const mintAmount = ethers.parseEther("1000"); + await expect( + myToken.connect(addr1).mint(addr2.address, mintAmount) + ).to.be.reverted; + }); + }); +}); diff --git a/test/SimpleStorage.test.js b/test/SimpleStorage.test.js new file mode 100644 index 0000000..d6be4f3 --- /dev/null +++ b/test/SimpleStorage.test.js @@ -0,0 +1,41 @@ +const { expect } = require("chai"); +const { ethers } = require("hardhat"); + +describe("SimpleStorage", function () { + let simpleStorage; + let owner; + let addr1; + + beforeEach(async function () { + [owner, addr1] = await ethers.getSigners(); + const SimpleStorage = await ethers.getContractFactory("SimpleStorage"); + simpleStorage = await SimpleStorage.deploy(); + }); + + describe("Deployment", function () { + it("Should start with a value of 0", async function () { + expect(await simpleStorage.get()).to.equal(0); + }); + }); + + describe("Set and Get", function () { + it("Should store the value 42", async function () { + await simpleStorage.set(42); + expect(await simpleStorage.get()).to.equal(42); + }); + + it("Should emit ValueChanged event", async function () { + await expect(simpleStorage.set(100)) + .to.emit(simpleStorage, "ValueChanged") + .withArgs(100, owner.address); + }); + + it("Should update the value multiple times", async function () { + await simpleStorage.set(10); + expect(await simpleStorage.get()).to.equal(10); + + await simpleStorage.set(20); + expect(await simpleStorage.get()).to.equal(20); + }); + }); +}); From 6beb4e21c8eaf4fcc2e6e69b6f4c0abde132e68a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 18:16:37 +0000 Subject: [PATCH 3/3] Add security: Set explicit permissions in GitHub Actions workflow Co-authored-by: wessel05j <146479070+wessel05j@users.noreply.github.com> --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e878eaa..b1e3006 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main, develop ] +permissions: + contents: read + jobs: test: runs-on: ubuntu-latest