diff --git a/.lintstagedrc.js b/.lintstagedrc.js index 0bc84d57..121d5b07 100644 --- a/.lintstagedrc.js +++ b/.lintstagedrc.js @@ -1,8 +1,21 @@ const path = require('path'); -const buildTextLintCommand = (filenames) => `textlint ${filenames - .map((f) => path.relative(process.cwd(), f)) - .join(' ')}` +const buildTextLintCommand = (filenames) => { + // Filter out files that should be ignored + const filtered = filenames.filter(f => { + const relative = path.relative(process.cwd(), f); + // Exclude translation-related English docs and English translations + return !relative.includes('TRANSLATION_GUIDE.md') && + !relative.includes('TRANSLATION_STATUS.md') && + !relative.includes('i18n/en/'); + }); + + if (filtered.length === 0) return 'echo "No files to lint"'; + + return `textlint ${filtered + .map((f) => path.relative(process.cwd(), f)) + .join(' ')}`; +}; module.exports = { "docs/**/*.md": [buildTextLintCommand] diff --git a/.textlintignore b/.textlintignore index b5248bde..39084bfb 100644 --- a/.textlintignore +++ b/.textlintignore @@ -1,2 +1,5 @@ public README.md +docs/TRANSLATION_GUIDE.md +docs/TRANSLATION_STATUS.md +i18n/en/** diff --git a/docs/TRANSLATION_GUIDE.md b/docs/TRANSLATION_GUIDE.md new file mode 100644 index 00000000..84aabe91 --- /dev/null +++ b/docs/TRANSLATION_GUIDE.md @@ -0,0 +1,209 @@ +# Translation Guide for UNCHAIN Projects + +This guide explains how to translate UNCHAIN learning content from Japanese to English. + +## Overview + +UNCHAIN projects use Docusaurus for documentation with built-in i18n (internationalization) support. English translations are stored in a separate directory structure that mirrors the original Japanese content. + +## Directory Structure + +### Japanese (Original) +``` +docs/ + └── [Chain]/ + └── [Project-Name]/ + ├── index.md + ├── section-1/ + │ ├── lesson-0.md + │ ├── lesson-1.md + │ └── ... + └── section-2/ + └── ... +``` + +### English (Translation) +``` +i18n/en/docusaurus-plugin-content-docs/current/ + └── [Chain]/ + └── [Project-Name]/ + ├── index.md + ├── section-1/ + │ ├── lesson-0.md + │ ├── lesson-1.md + │ └── ... + └── section-2/ + └── ... +``` + +## Translation Process + +### 1. Choose a Project + +See [issue #3526](https://github.com/unchain-tech/UNCHAIN-projects/issues/3526) for the list of projects needing translation. Comment on the issue to claim a project before starting. + +### 2. Create Directory Structure + +Create the corresponding directory structure in the English translation folder: + +```bash +mkdir -p i18n/en/docusaurus-plugin-content-docs/current/[Chain]/[Project-Name] +``` + +### 3. Translate Files + +For each markdown file: + +#### Elements to Translate: +- ✅ Title in YAML frontmatter +- ✅ All Japanese text content +- ✅ Image alt text (in `![alt text](url)`) +- ✅ Link text (in `[link text](url)`) + +#### Elements to Keep Unchanged: +- ❌ Code blocks (```) +- ❌ Image URLs +- ❌ Link URLs +- ❌ Emojis (👋, 🎉, etc.) +- ❌ File/folder names in paths + +### 4. Translation Tips + +#### Standard Sections + +Many documents have standard sections that should be translated consistently: + +**"プロジェクトをアップグレードする"** → **"Upgrading this Project"** + +**"質問する"** → **"Asking Questions"** + +#### Common Terms + +| Japanese | English | +|----------|---------| +| スマートコントラクト | Smart Contract | +| ブロックチェーン | Blockchain | +| ウォレット | Wallet | +| デプロイ | Deploy | +| ミント | Mint | +| トークン | Token | +| ガス代 | Gas Fee | + +#### Link Translations + +For GitHub documentation links, change `ja` to `en` in URLs: +- `https://docs.github.com/ja/...` → `https://docs.github.com/en/...` + +### 5. Quality Checks + +Before submitting: + +- [ ] All markdown files have corresponding English versions +- [ ] YAML frontmatter is properly formatted +- [ ] Code blocks are intact +- [ ] Images display correctly +- [ ] Links work properly +- [ ] Build succeeds: `yarn build` +- [ ] Content makes sense in English + +## Using AI Translation Tools + +While AI translation (ChatGPT, Claude, DeepL, etc.) can speed up the process, **always review and edit the output**: + +1. **Preserve Markdown Structure**: Ensure code blocks, links, and images remain intact +2. **Natural English**: Fix awkward phrasings, make it sound natural +3. **Technical Accuracy**: Verify technical terms are correct +4. **Consistency**: Use the same terms throughout the project + +### Example Prompt for AI Translation: + +``` +Translate the following Japanese markdown document to English. + +Requirements: +- Keep all markdown formatting intact +- Do NOT translate code blocks (enclosed in ```) +- Do NOT translate image URLs +- Do NOT translate link URLs (but DO translate link text) +- Keep all emojis unchanged +- Translate the YAML frontmatter title +- Use natural English suitable for technical documentation + +[Paste Japanese markdown here] +``` + +## Testing Translations + +### Local Development + +1. Install dependencies: +```bash +yarn install +``` + +2. Start development server: +```bash +yarn start +``` + +3. View English version: +```bash +yarn start --locale en +``` + +4. Build to check for errors: +```bash +yarn build +``` + +### Viewing Translations + +Once deployed, English translations will be available at: +`https://buidl.unchain.tech/[Project-Name]/en/` + +## Examples + +Refer to these existing translations for examples: + +- **Polygon-Whitelist-NFT**: [Japanese docs](https://buidl.unchain.tech/Polygon-Whitelist-NFT/) → [English](https://buidl.unchain.tech/Polygon-Whitelist-NFT/en/) +- **TheGraph-ScaffoldEth2**: [Japanese docs](https://buidl.unchain.tech/TheGraph-ScaffoldEth2/) → [English](https://buidl.unchain.tech/TheGraph-ScaffoldEth2/en/) +- **AVAX-AMM**: [Japanese docs](https://buidl.unchain.tech/AVAX-AMM/) → [English](https://buidl.unchain.tech/AVAX-AMM/en/) + +## Submitting Your Translation + +1. Create a new branch: +```bash +git checkout -b translate/[project-name] +``` + +2. Commit your changes: +```bash +git add i18n/en/docusaurus-plugin-content-docs/current/[Chain]/[Project-Name] +git commit -m "Add English translation for [Project-Name]" +``` + +3. Push to your fork: +```bash +git push origin translate/[project-name] +``` + +4. Create a Pull Request on GitHub + +5. In the PR description: + - Mention which project you translated + - Reference issue #3526 + - Note if you used AI translation tools (for transparency) + +## Getting Help + +- **Discord**: Join the UNCHAIN Discord community +- **GitHub Issues**: Comment on [issue #3526](https://github.com/unchain-tech/UNCHAIN-projects/issues/3526) +- **Examples**: Review existing translations for guidance + +## Project Status + +Track translation progress on [issue #3526](https://github.com/unchain-tech/UNCHAIN-projects/issues/3526). + +--- + +Thank you for contributing to make UNCHAIN learning content accessible to English speakers! 🌍✨ diff --git a/docs/TRANSLATION_STATUS.md b/docs/TRANSLATION_STATUS.md new file mode 100644 index 00000000..fce2355b --- /dev/null +++ b/docs/TRANSLATION_STATUS.md @@ -0,0 +1,130 @@ +# Translation Status + +This document tracks the progress of translating UNCHAIN learning content from Japanese to English. + +**Last Updated**: 2025-11-08 + +## Overview + +- **Total Projects**: 25 +- **Completed**: 3 (12%) +- **In Progress**: 1 (4%) +- **Pending**: 21 (84%) + +## Translation Infrastructure + +✅ **Translation Guide**: [`docs/TRANSLATION_GUIDE.md`](./TRANSLATION_GUIDE.md) +- Comprehensive step-by-step guide for contributors +- Common terms glossary +- AI translation tool tips +- Quality checklist + +✅ **Helper Script**: [`scripts/prepare-translation.sh`](../scripts/prepare-translation.sh) +- Automates directory structure creation +- Shows translation progress +- Provides next steps guidance + +✅ **Linting Configuration**: Updated for English content +- `.textlintignore` excludes English files +- `.lintstagedrc.js` skips Japanese rules for English content + +## Project Status + +### ✅ Completed (3) + +| ID | Project | Chain | Files | Link | +|----|---------|-------|-------|------| +| 204 | Polygon-Whitelist-NFT | Polygon | All | [View](https://buidl.unchain.tech/Polygon-Whitelist-NFT/en/) | +| 502 | AVAX-AMM | Avalanche | All | [View](https://buidl.unchain.tech/AVAX-AMM/en/) | +| 901 | TheGraph-ScaffoldEth2 | TheGraph | All | [View](https://buidl.unchain.tech/TheGraph-ScaffoldEth2/en/) | + +### 🔄 In Progress (1) + +| ID | Project | Chain | Progress | Notes | +|----|---------|-------|----------|-------| +| 101 | ETH-dApp | Ethereum | 3/14 files | Sample translations as examples | + +### 📋 Pending (21) + +#### Ethereum (5) +- [ ] 102 - ETH-NFT-Collection +- [ ] 103 - ETH-NFT-Maker +- [ ] 104 - ETH-NFT-Game +- [ ] 105 - ETH-Yield-Farm +- [ ] 106 - ETH-DAO + +#### Polygon (3) +- [ ] 201 - Polygon-Generative-NFT +- [ ] 202 - Polygon-ENS-Domain +- [ ] 203 - Polygon-Mobile-dApp + +#### Solana (4) +- [ ] 301 - Solana-dApp +- [ ] 302 - Solana-NFT-Drop +- [ ] 303 - Solana-Online-Store +- [ ] 304 - Solana-Wallet + +#### NEAR (4) +- [ ] 401 - NEAR-Election-dApp +- [ ] 402 - NEAR-Hotel-Booking-dApp +- [ ] 403 - NEAR-BikeShare +- [ ] 404 - NEAR-MulPay + +#### Avalanche (3) +- [ ] 501 - AVAX-Messenger +- [ ] 503 - AVAX-Asset-Tokenization +- [ ] 504 - AVAX-Subnet + +#### Other Chains (2) +- [ ] 601 - ICP-Static-Site (ICP) +- [ ] 701 - ASTAR-SocialFi (Astar) +- [ ] 801 - XRPL-NFT-Maker (XRPL) + +## How to Contribute + +1. **Choose a project** from the pending list above +2. **Comment on [issue #3526](https://github.com/unchain-tech/UNCHAIN-projects/issues/3526)** to claim it +3. **Follow the guide** in [`docs/TRANSLATION_GUIDE.md`](./TRANSLATION_GUIDE.md) +4. **Use the helper script**: `./scripts/prepare-translation.sh docs/[Chain]/[Project]` +5. **Translate** the markdown files +6. **Test**: `yarn build` +7. **Submit a PR** + +## Translation Workflow + +``` +1. Select Project → 2. Claim in Issue → 3. Prepare Structure + ↓ +4. Translate Files → 5. Review & Test → 6. Submit PR +``` + +## Quality Standards + +All translations should: +- ✅ Maintain markdown structure and formatting +- ✅ Keep code blocks unchanged +- ✅ Preserve image URLs and link URLs +- ✅ Translate link text and alt text +- ✅ Use consistent technical terminology +- ✅ Pass build without errors +- ✅ Follow existing translation examples + +## Resources + +- **Translation Guide**: [`docs/TRANSLATION_GUIDE.md`](./TRANSLATION_GUIDE.md) +- **Issue Tracker**: [#3526](https://github.com/unchain-tech/UNCHAIN-projects/issues/3526) +- **Example Translations**: + - [Polygon-Whitelist-NFT](https://github.com/unchain-tech/UNCHAIN-projects/tree/main/i18n/en/docusaurus-plugin-content-docs/current/Polygon/Polygon-Whitelist-NFT) + - [TheGraph-ScaffoldEth2](https://github.com/unchain-tech/UNCHAIN-projects/tree/main/i18n/en/docusaurus-plugin-content-docs/current/TheGraph/TheGraph-ScaffoldEth2) + - [AVAX-AMM](https://github.com/unchain-tech/UNCHAIN-projects/tree/main/i18n/en/docusaurus-plugin-content-docs/current/Avalanche/AVAX-AMM) +- **Discord**: UNCHAIN Community + +## Notes for Translators + +- **AI Translation Tools**: You can use ChatGPT, Claude, DeepL, etc. to speed up translation, but **always review and edit** the output for accuracy and natural English. +- **Technical Terms**: Refer to the glossary in the Translation Guide for consistency. +- **Questions**: Ask in Discord or comment on the issue. + +--- + +Let's make UNCHAIN learning content accessible to English speakers worldwide! 🌍✨ diff --git a/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/index.md b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/index.md new file mode 100644 index 00000000..72844da5 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/index.md @@ -0,0 +1,3 @@ +# ETH-dApp + +![](/metadata/ETH-dApp/learn-banner.png) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-0.md b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-0.md new file mode 100644 index 00000000..3646650c --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-0.md @@ -0,0 +1,118 @@ +--- +title: Build a Web App on the Ethereum Network +--- +### 👋 Welcome to the dApp Development Project! + +In this project, we will implement a smart contract on the Ethereum network and build a custom web application that can interact with the smart contract. + +To proceed with this project, you will need the following skills: + +- [Terminal operations](https://qiita.com/ryouzi/items/f9dee1540a04a0bfb9a3) +- [Javascript](https://developer.mozilla.org/en/docs/Web/JavaScript) +- [React.js](https://reactjs.org/) + +You don't need to understand everything right now. +If you have any questions, search the internet or ask in the community as you work through the project! +If you're new to development, we recommend starting with this project ☺️ + +### ⛓ What is Blockchain? + +Blockchain is a peer-to-peer network of computers (nodes) that communicate with each other. + +It's a decentralized network where all participants share responsibility for operating the network, so each network participant maintains a copy of the code and data on the blockchain. + +All this data is contained in bundles of records called "blocks," which are "chained" together to form a blockchain. + +Every node on the network ensures that this data is secure and immutable, unlike centralized applications where code and data can be changed at any time. This is what makes blockchain powerful ✨ + +Because blockchain is responsible for storing data, it is fundamentally a database. + +And since it's a network of computers talking to each other, it's a network. You can think of it as a unified combination of network and database. + +Another fundamental difference between traditional web applications and blockchain applications is that the application does not manage any user data. User data is managed by the blockchain. + +### 🥫 What is a Smart Contract? + +A smart contract is a mechanism that automatically executes contracts on the blockchain. + +A common analogy is a vending machine. A vending machine has a program that says "when 100 yen is inserted and a button is pressed, drop a drink," and doesn't require the process of "a clerk receiving money and handing over a drink." + +The reason smart contracts are called "smart" is precisely because they eliminate human intervention and execute programs automatically. + +In practice, smart contracts consist of programs that are replicated and processed across all computers on the Ethereum network. + +Due to Ethereum's versatility, you can build applications on its network. + +All smart contract code is immutable, meaning it **cannot be changed**. + +In other words, once you deploy a smart contract to the blockchain, you cannot change or update the code. + +This is a design feature to ensure code reliability and security. + +I often compare smart contracts to microservices on the web. They function as an interface for reading and writing data from the blockchain and executing business logic. They are publicly accessible, meaning anyone who can access the blockchain can access that interface. + +### 📱 What are dApps? + +dApps stands for **decentralized Applications**. + +dApps refer to applications that combine smart contracts built on the blockchain with a frontend user interface (such as a website). + +dApps are built on Solidity, Ethereum's programming language. + +In Ethereum, smart contracts are accessible to anyone like open APIs. Therefore, you can call smart contracts written by others from your web application. And vice versa. + +### 🛠 What Will We Build? + +We will build a **decentralized web application (dApp)** called WavePortal. + +WavePortal will implement the following features: + +1. Anyone on the internet can send you a "👋 + message". +2. That data will be stored on the blockchain via an Ethereum smart contract. +3. Users who wave to you might get lucky and win a small amount of ETH from your site 🎉 + +In this project, we will specifically implement: + +- Connecting users' wallets to your WavePortal. +- Implementing functionality that allows users to interact with smart contracts through the web application. + +We'll implement the backend in Solidity and build the frontend in React. + +### 🌍 Upgrading this Project + +This learning content is operated under [Attribution-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-sa/4.0/) © 2022 buildspace license and [UNCHAIN License](https://github.com/unchain-tech/UNCHAIN-projects/blob/main/LICENSE). + +If you're participating in the project and think, "This could be clearer if done this way!" or "This is incorrect!", please feel free to send a `pull request`. + +For instructions on how to edit code directly from GitHub and send a `pull request` directly, see [here](https://docs.github.com/en/repositories/working-with-files/managing-files/editing-files#editing-files-in-another-users-repository). + +Any requests are welcome 🎉 + +You can also `Fork` the project to your own GitHub account, edit the contents, and send a `pull request`. + +- For instructions on how to `Fork` a project, see [here](https://docs.github.com/en/get-started/quickstart/fork-a-repo). +- For instructions on how to create a `pull request` from a `Fork`, see [here](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork). + +**👋 Send a `pull request` to `UNCHAIN-projects`! ⏩ Visit [UNCHAIN's GitHub](https://github.com/unchain-tech/UNCHAIN-projects)!** + +### ⚡️ Create an `Issue` + +If you feel that you don't need to send a `pull request` but want to leave a suggestion, you can create an `Issue` [here](https://github.com/unchain-tech/UNCHAIN-projects/issues). + +For instructions on how to create an `Issue`, see [here](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-an-issue). + +Creating `pull requests` and `issues` are important tasks when actually developing as a team, so please give it a try. + +Let's make UNCHAIN projects better together ✨ + +--- + +Let's move on to the next lesson and set up your programming environment 🎉 + +--- + +Attribution: This learning content is licensed under [Attribution-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-sa/4.0/) © 2022 buildspace. +Sharelike: Translations and modifications to markdown documents. + +Documentation created by [yukis4san](https://github.com/yukis4san)(UNCHAIN discord ID: yshimura#7617) + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-1.md b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-1.md new file mode 100644 index 00000000..99643571 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-1.md @@ -0,0 +1,80 @@ +--- +title: Launch an Ethereum Network in Your Local Environment +--- +### ✅ Setting Up the Environment + +Here's the overall picture of this project: + +1\. **Create a smart contract.** + +- Implement all the logic for how users can send you a "👋 (wave)" on the smart contract. +- A smart contract is like **server code**. + +2\. **Deploy the smart contract onto the blockchain.** + +- Anyone in the world can access your smart contract. +- **The blockchain acts as a server.** + +3\. **Build a web application (dApp)**. + +- Users can easily interact with your smart contract deployed on the blockchain through a website. +- Smart contract implementation + frontend user interface creation 👉 Let's aim to complete the dApp 🎉 + +First, you need to have `Node.js`. If you don't have it, visit [here](https://hardhat.org/tutorial/setting-up-the-environment#installing-node.js) to install it. The recommended version for this project is `v20`. + +Once the installation is complete, run the following command in your terminal to check the version: + +``` +$ node -v +v20.5.0 +``` + +### 🍽 Fork the Git Repository to Your GitHub + +If you don't have a GitHub account yet, follow the steps [here](https://qiita.com/okumurakengo/items/848f7177765cf25fcde0) to create one. + +If you already have a GitHub account, follow the steps below to [fork](https://denno-sekai.com/github-fork/) the repository that will serve as the foundation for the project to your GitHub. + +1. Access the ETH-dApp repository from [here](https://github.com/unchain-tech/ETH-dApp) and click the `Fork` button at the top right of the page. + +![](/images/ETH-dApp/section-1/1_1_1.png) + +2. The Create a new fork page will open, so **make sure the item "Copy the `main` branch only" is checked**. + +![](/images/ETH-dApp/section-1/1_1_2.png) + +Once the settings are complete, click the `Create fork` button. Confirm that a fork of the `ETH-dApp` repository has been created in your GitHub account. + +Now, let's clone the forked repository to your local environment. + +First, as shown in the figure below, click the `Code` button, select `SSH`, and copy the Git link. + +![](/images/ETH-dApp/section-1/1_1_3.png) + +Navigate to any directory where you want to work in your terminal and execute the following using the link you just copied: + +``` +git clone copied_github_link +``` + +Once it's successfully cloned, you're ready for local development. + +### 🔍 Checking the Folder Structure + +Before diving into implementation, let's check the folder structure. The cloned starter project should look like this: + +``` +ETH-dApp +├── .git/ +├── .gitignore +├── .yarnrc.yml +├── LICENSE +├── README.md +├── package.json +├── packages/ +│ ├── client/ +│ └── contract/ +└── yarn.lock +``` + +The starter project uses a monorepo structure. A monorepo is a method of managing all code for contracts and clients (or other components) together in a single repository. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-2.md b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-2.md new file mode 100644 index 00000000..5ec7c1a1 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-2.md @@ -0,0 +1,120 @@ +--- +title: Create a Smart Contract with Solidity +--- +### 👩‍💻 Creating a Contract + +We'll create a smart contract that tracks the total number of "👋 (waves)". The smart contract we create here can be freely modified later to suit your use case. + +Create a file named `WavePortal.sol` under the `contracts` directory. + +When using Hardhat, the file structure is very important, so you need to be careful. If your file structure looks like the following, you're good to go 😊 + +``` +packages/ +└── contract/ + └── contracts/ + └── WavePortal.sol +``` + +Next, open the project code in your code editor. + +We recommend using VS Code. You can download it from [here](https://azure.microsoft.com/en-us/products/visual-studio-code/). + +See [here](https://maku.blog/p/f5iv9kx/) for how to launch VS Code from the terminal. + +- Run the `code` command in your terminal + +This will make it much easier to launch VS Code in the future, so please give it a try. + +As a coding support tool, we recommend downloading the Solidity extension on VS Code. + +You can download it from [here](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity). + +Now, let's create the contents of `WavePortal.sol`. + +Open `WavePortal.sol` in VS Code and enter the following: + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import "hardhat/console.sol"; + +contract WavePortal { + constructor() { + console.log("Here is my first smart contract!"); + } +} +``` + +Let's look at the code in detail. + +```solidity +// SPDX-License-Identifier: MIT +``` + +This is called an "SPDX License Identifier" and is an identifier that makes the type of software license immediately recognizable. + +For more details, please refer to [here](https://www.skyarch.net/blog/?p=15940). + +```solidity +pragma solidity ^0.8.19; +``` + +This is the version of the Solidity compiler used by the contract. + +The above code declares that we will only use compiler version `0.8.19` or higher and below version `0.9.0`, and will not use any other versions. + +Make sure the compiler version is the same as what's listed in `hardhat.config.js`. + +If the Solidity version listed in `hardhat.config.js` is not `0.8.19`, change the contents of `WavePortal.sol` to match the version listed in `hardhat.config.js`. + +```solidity +import "hardhat/console.sol"; +``` + +We're importing Hardhat's `console.sol` file to output console logs to the terminal when executing the contract. + +This is a very useful tool for debugging smart contracts in the future. + +```solidity +contract WavePortal { + constructor() { + console.log("Here is my first smart contract!"); + } +} +``` + +`contract` is like a "[class](https://wa3.i-3-i.info/word1120.html)" in other languages. + +When you initialize this `contract`, the `constructor` is executed and the contents of `console.log` are displayed in the terminal. + +For more on the concept of classes, refer to [here](https://aiacademy.jp/media/?p=131). + +### 🔩 What is a Constructor? + +`constructor` is an optional function used to initialize the state variables of a `contract`. + +We'll explain this in more detail later, so for now, please understand the following characteristics of `constructor`: + +- A `contract` can only have one `constructor`. +- The `constructor` is executed only once when the smart contract is created and is used to initialize the state of the `contract`. +- After the `constructor` is executed, the code is deployed to the blockchain. + +### 🙋‍♂️ Asking Questions + +If you have any questions about the work so far, please ask in Discord's `#ethereum` channel. + +To help the process of providing assistance flow smoothly, please include the following 3 points in your error report ✨ + +``` +1. Section number and lesson number related to the question +2. What you were trying to do +3. Copy & paste the error message +4. Screenshot of the error screen +``` + +--- + +In the next lesson, we'll run the smart contract. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-3.md b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-3.md new file mode 100644 index 00000000..2afd6b61 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-3.md @@ -0,0 +1,174 @@ +--- +title: Compile and Run the Contract in Your Local Environment +--- +### 🔥 Run the Smart Contract in Your Local Environment + +In the previous lesson, we created a smart contract called `WavePortal.sol`. + +In this lesson, we will: + +1. Compile `WavePortal.sol`. +2. Deploy `WavePortal.sol` on the blockchain in your local environment. +3. Once the above is complete, verify that the contents of `console.log` are displayed in the terminal. + +The ultimate goal of this project is to get your smart contract on the blockchain so that people around the world can access it through your web application. + +First, let's do the above work in your local environment. + +### 📝 Create a Program to Run the Contract + +Navigate to the `scripts` directory and create a file named `run.js`. + +**`run.js` is a program for testing smart contracts in your local environment.** + +Write the following in `run.js`: + +```js +const main = async () => { + const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); + const waveContract = await waveContractFactory.deploy(); + const wavePortal = await waveContract.deployed(); + + console.log("WavePortal address: ", wavePortal.address); +}; + +const runMain = async () => { + try { + await main(); + process.exit(0); + } catch (error) { + console.log(error); + process.exit(1); + } +}; + +runMain(); +``` + +Let's deepen our understanding of the code line by line. + +```js +const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); +``` + +This compiles the `WavePortal` contract. + +Once the contract is compiled, the files needed to handle the contract are generated directly under the `artifacts` directory. + +> ✍️: About `hre.ethers.getContractFactory` +> The `getContractFactory` function links the address of the library that supports deployment with the `WavePortal` contract. +> +> `hre.ethers` is a specification of the Hardhat plugin. + +> ✍️: About `const main = async ()` and `await` +> When writing code in Javascript, you may run into problems where code doesn't execute in order from top to bottom. This is called an asynchronous processing problem. +> +> One solution is to use `async` / `await` as we do here. +> +> With this, no other processing in the `main` function will occur until the processing prefixed with `await` is finished. +> +> This means that other processing written in the `main` function will not be executed until `hre.ethers.getContractFactory('WavePortal')` is finished. + +Next, let's look at the following process: + +```js +const waveContract = await waveContractFactory.deploy(); +``` + +Hardhat creates a local Ethereum network just for the contract. + +Then, after the script finishes running, it destroys that local network. + +In other words, every time you run the contract, the blockchain becomes new, as if you were refreshing a local server each time. + +- Since it's always a zero reset, it makes debugging errors easier. + +Next, let's look at the following process: + +```js +const wavePortal = await waveContract.deployed(); +``` + +Here, we're processing to wait until the `WavePortal` contract is deployed to the local blockchain. + +Hardhat actually creates a "miner" on your machine and builds the blockchain. + +The `constructor` is executed for the first time when the contract is deployed. + +Finally, let's look at the following process: + +```js +console.log("WavePortal address:", wavePortal.address); +``` + +Finally, once deployed, `wavePortal.address` outputs the address of the deployed contract. + +From this address, we can find the contract on the blockchain, but since we're implementing it on a local Ethereum network (= blockchain) this time, not everyone in the world can access it. + +On the other hand, if we had deployed to the blockchain on the Ethereum mainnet, anyone in the world could access the contract. + +There are already millions of smart contracts deployed on the actual blockchain. + +As long as we know the address, we can easily access contracts we're interested in from anywhere in the world. + +### 🪄 Let's Run It + +Edit the `script` section of `packages/contract/package.json` as follows: + +```json + "scripts": { + "run:script": "npx hardhat run scripts/run.js", + "test": "npx hardhat test", + "deploy": "npx hardhat run scripts/deploy.js --network sepolia" + }, +``` + +After that, make sure you're in the root directory and run the following in your terminal: + +``` +yarn contract run:script +``` + +Verify that the contents of `console.log` and the contract address are displayed in the terminal. + +Example output in terminal: + +``` +Compiled 2 Solidity files successfully +Here is my first smart contract! +WavePortal address: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +``` + +If output like the above is displayed in the terminal, the test is successful. + +### 🎩 About Hardhat Runtime Environment + +In `run.js`, `hre.ethers` appears. + +However, `hre` is not imported anywhere. Why is that? + +The answer is that Hardhat is calling the Hardhat Runtime Environment (HRE). + +HRE is an object (= bundle of code) that contains all the functionality prepared by Hardhat. + +Every time you run a terminal command starting with `hardhat`, you're accessing the HRE, so there's no need to import `hre` into `run.js`. + +For more details, see the [Hardhat official documentation](https://hardhat.org/advanced/hardhat-runtime-environment.html). + +### 🙋‍♂️ Asking Questions + +If you have any questions about the work so far, please ask in Discord's `#ethereum` channel. + +To help the process of providing assistance flow smoothly, please include the following 3 points in your error report ✨ + +``` +1. Section number and lesson number related to the question +2. What you were trying to do +3. Copy & paste the error message +4. Screenshot of the error screen +``` + +--- + +Once you can output the contents of `console.log` and the contract address in the terminal, proceed to the next lesson 🎉 + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-4.md b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-4.md new file mode 100644 index 00000000..3c5ca0f4 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-4.md @@ -0,0 +1,420 @@ +--- +title: Store Data in Your Smart Contract +--- +### 📦 Let's Store Data + +In this lesson, you'll learn how to store the number of "👋 (waves)" that users have sent you as data. + +Blockchain is like a server that can store data on the cloud like AWS. + +However, no one owns that data. + +Around the world, there are people called "miners" who do the work of storing data on the blockchain. We pay for this work. + +That payment is commonly called **gas fees**. + +When writing data to the Ethereum blockchain, we pay `$ETH` to "miners" as payment. + +Now, let's update `WavePortal.sol` to save "👋 (waves)". + +```solidity +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import "hardhat/console.sol"; + +contract WavePortal { + + uint256 private _totalWaves; + + constructor() { + console.log("Here is my first smart contract!"); + } + + function wave() public { + _totalWaves += 1; + console.log("%s has waved!", msg.sender); + } + + function getTotalWaves() public view returns (uint256) { + console.log("We have %d total waves!", _totalWaves); + return _totalWaves; + } +} +``` + +Let's deepen our understanding of the newly added code. + +```solidity +uint256 private _totalWaves; +``` + +A `_totalWaves` variable has been added that is automatically initialized to `0`. This variable is called a "state variable" and is permanently stored in the storage of the `WavePortal` contract. + +- [uint256](https://www.iuec.co.jp/blockchain/uint256.html) means "unsigned integer data type" that can handle very large numbers. + +### 🎁 About Solidity Access Modifiers + +```solidity +function wave() public { + _totalWaves += 1; + console.log("%s has waved!", msg.sender); +} +``` + +Here, a `wave()` function has been added to record the number of "👋 (waves)". First, let's look at `public`. + +This is one of Solidity's access modifiers. + +In Solidity and various other languages, you need to specify access permissions for each function. Access modifiers do that specification. + +Solidity has four access modifiers: + +- **`public`**: Functions and variables defined with `public` can be called from the contract where they are defined, from other contracts that inherit that contract, and from outside those contracts - **basically from anywhere**. In Solidity, **functions** without an access modifier are automatically treated as `public`. + +- **`private`**: Functions and variables defined with `private` can **only** be called **from the contract where they are defined**. + +- **`internal`**: Functions and variables defined with `internal` can be called from **both** **the contract where they are defined** and **other contracts that inherit that contract**. In Solidity, **variables** without an access modifier are automatically treated as `internal`. + +- **`external`**: Functions and variables defined with `external` can **only** be called **from outside**. + +The following summarizes Solidity's access modifiers and access permissions: + +![](/images/ETH-dApp/section-1/1_4_1.png) + +Since Solidity access modifiers will appear frequently from now on, it's okay if you can understand them roughly for now. + +### 🔍 About `msg.sender` + +```solidity +function wave() public { + _totalWaves += 1; + console.log("%s has waved!", msg.sender); +} +``` + +Did you notice that `msg.sender` appears in the `wave()` function? + +The value that goes into `msg.sender` is, simply put, **the wallet address of the person who called the function (= the person who sent you a "👋 (wave)")**. + +This is like **user authentication**. + +- To call a function included in a smart contract, users need to connect a valid wallet. +- `msg.sender` accurately identifies who called the function and performs user authentication. + +### 🖋 About Solidity Function Modifiers + +Solidity has modifiers (= function modifiers) that are used only for functions. + +In Solidity development, if you're not conscious of function modifiers, the cost (= gas fees) of recording data can skyrocket, so you need to be careful. + +The key point here is that **you need to pay gas fees to write values to the blockchain, but you don't need to pay gas fees if you're only referencing values from the blockchain.** + +Here, I'll introduce two main function modifiers: + +- **`view`**: A `view` function is a read-only function that ensures state variables defined in the function are not changed after the function is called. +- **`pure`**: A `pure` function doesn't read or modify state variables defined in the function, but returns values using only parameters passed to the function or local variables that exist in the function. + +The following summarizes Solidity's function modifiers `pure` and `view`: + +![](/images/ETH-dApp/section-1/1_4_2.png) + +What you should understand so far is that using `pure` or `view` functions can **reduce gas fees**. + +At the same time, by not writing data to the blockchain, **processing speed also improves**. + +Let's look at the following function added to `WavePortal.sol`: + +```solidity +function wave() public { + _totalWaves += 1; + console.log("%s has waved!", msg.sender); +} +``` + +Did you notice that the `wave()` function has no function modifier? + +- The number of "👋 (waves)" sent by the same user is counted by `_totalWaves += 1` and data is written to the blockchain. +- Also, when this function is called, `console.log("%s has waved!", msg.sender)` displays the address of the user who sent you a "👋 (wave)" in the terminal. + +Now, let's also look at the following code: + +```solidity +function getTotalWaves() public view returns (uint256) { + console.log("We have %d total waves!", _totalWaves); + return _totalWaves; +} +``` + +On the other hand, the `getTotalWaves()` function with the `view` function modifier only references the total number of "👋 (waves)" users have sent you. + +### ✅ Update `run.js` to Call Functions + +Next, let's update `run.js` as follows: + +```js +const main = async () => { + const [owner, randomPerson] = await hre.ethers.getSigners(); + const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); + const waveContract = await waveContractFactory.deploy(); + const wavePortal = await waveContract.deployed(); + + console.log("Contract deployed to:", wavePortal.address); + console.log("Contract deployed by:", owner.address); + + let waveCount; + waveCount = await waveContract.getTotalWaves(); + + let waveTxn = await waveContract.wave(); + await waveTxn.wait(); + + waveCount = await waveContract.getTotalWaves(); +}; + +const runMain = async () => { + try { + await main(); + process.exit(0); + } catch (error) { + console.log(error); + process.exit(1); + } +}; + +runMain(); +``` + +The `wave()` and `getTotalWaves()` functions specified as `public` in `WavePortal.sol` can now be called on the blockchain. + +Let's call those functions from `run.js`. + +- As a review, `run.js` is test code for debugging. +- `run.js` is created to test whether the code runs without problems, assuming a situation where users call your smart contract in the production environment. + +Functions defined as `public` are like API endpoints. + +Let's look at the updated parts line by line. + +```js +const [owner, randomPerson] = await hre.ethers.getSigners(); +``` + +When deploying the `WavePortal` contract to the blockchain, we need the wallet address of the side sending "👋 (waves)". + +`hre.ethers.getSigners()` is a function provided by Hardhat that returns arbitrary addresses. + +- Here, Hardhat generates a wallet address for the contract owner (= you) and a wallet address for a user who will send you a "👋 (wave)", storing them in variables called `owner` and `randomPerson` respectively. + +- Think of `randomPerson` as a user who will send "👋 (waves)" in the test environment. + +Next, let's look at the following code: + +```js +console.log("Contract deployed to:", wavePortal.address); +``` + +Here, we're outputting the address where your smart contract was deployed (= `wavePortal.address`) to the terminal. + +```js +console.log("Contract deployed by:", owner.address); +``` + +Here, we're outputting the address (= `owner.address`) of the person who deployed the `WavePortal` contract (= you) to the terminal. + +Finally, let's look at the following code: + +```js +let waveCount; +waveCount = await waveContract.getTotalWaves(); + +let waveTxn = await waveContract.wave(); +await waveTxn.wait(); + +waveCount = await waveContract.getTotalWaves(); +``` + +Here, we're manually calling functions just like a normal API. Let's look at it line by line. + +```js +let waveCount; +waveCount = await waveContract.getTotalWaves(); +``` + +First, we declare a local variable with `let waveCount`. + +Next, we call `getTotalWaves()` written in `WavePortal.sol` with `waveContract.getTotalWaves()` to get the existing total number of "👋 (waves)". + +```js +let waveTxn = await waveContract.wave(); +await waveTxn.wait(); +``` + +With `let waveTxn = await waveContract.wave()`, we're setting the frontend to wait for a response from the contract until the user approves that a new "👋 (wave)" has been sent. + +Since the `.wave()` function involves writing to the blockchain, gas fees are incurred. Therefore, users need to confirm the transaction. + +Have you ever used MetaMask and spent a few seconds approving a transaction? + +While you're approving, the code doesn't proceed to the next process and waits. + +After approval is finished, `await waveTxn.wait()` is executed and gets the result of the transaction. The code may feel redundant, but it's an important process. + +```js +waveCount = await waveContract.getTotalWaves(); +``` + +Finally here, we get `waveCount` one more time to check if it's been `+1`. + +### 🧙‍♀️ Let's Run the Test + +Make sure you're in the root directory and run the following in your terminal: + +``` +yarn contract run:script +``` + +Example terminal output: + +``` +Compiled 1 Solidity file successfully +Here is my first smart contract! +Contract deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +Contract deployed by: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +We have 0 total waves! +0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 has waved! +We have 1 total waves! +``` + +Did you get similar results in your terminal? + +This result shows that you are the `owner` of this smart contract and that you also sent yourself a "👋 (wave)". + +Therefore, the address following `Contract deployed by` and the address in "`0x...` has waved!" should match. + +The content implemented so far forms the basis of most smart contracts: + +1. Read a function. +2. Write a function. +3. Change state variables. + +These are important elements for building the WavePortal website. + +### 🤝 Have Other Users Send 👋 (waves) + +Here, we'll simulate the case where other users send you "👋 (waves)". + +Reflect the following in `run.js` and test what results appear in the terminal: + +```js +const main = async () => { + const [owner, randomPerson] = await hre.ethers.getSigners(); + const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); + const waveContract = await waveContractFactory.deploy(); + const wavePortal = await waveContract.deployed(); + + console.log("Contract deployed to:", wavePortal.address); + console.log("Contract deployed by:", owner.address); + + let waveCount; + waveCount = await waveContract.getTotalWaves(); + + let waveTxn = await waveContract.wave(); + await waveTxn.wait(); + + waveCount = await waveContract.getTotalWaves(); + + waveTxn = await waveContract.connect(randomPerson).wave(); + await waveTxn.wait(); + + waveCount = await waveContract.getTotalWaves(); +}; + +const runMain = async () => { + try { + await main(); + process.exit(0); + } catch (error) { + console.log(error); + process.exit(1); + } +}; + +runMain(); +``` + +The code added to `run.js` is as follows. Let's check it: + +```js +waveTxn = await waveContract.connect(randomPerson).wave(); +await waveTxn.wait(); +waveCount = await waveContract.getTotalWaves(); +``` + +Do you remember getting the `randomPerson` address in `run.js` at the beginning of this lesson? + +- `randomPerson` stores a random address obtained by Hardhat. +- `randomPerson` existed for this simulation. + +```js +waveTxn = await waveContract.connect(randomPerson).wave(); +``` + +Here, we're using `.connect(randomPerson)` to simulate another user sending you a "👋 (wave)". + +```js +await waveTxn.wait(); +waveCount = await waveContract.getTotalWaves(); +``` + +Here, just like you sent yourself a "👋 (wave)" and updated the value of `waveCount` after getting approval, we're checking `randomPerson`'s behavior before updating `waveCount` (`+1`). + +Now, let's update `run.js` and run the following: + +``` +yarn contract run:script +``` + +If results like the following are output to the terminal, it's successful. + +Example terminal output: + +``` +Here is my first smart contract! +Contract deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +Contract deployed by: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +We have 0 total waves! +0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 has waved! +We have 1 total waves! +0x70997970c51812dc3a010c7d01b50e0d17dc79c8 has waved! +We have 2 total waves! +``` + +Check that `#` in `We have # total waves!` is being updated. + +Since the first "👋 (wave)" is from yourself, confirm that the address displayed before `We have 1 total waves!` matches the address following `Contract deployed by`. + +The address following `We have 2 total waves!` is the address of `randomPerson` obtained by Hardhat. + +You can also add another person and run a simulation by adding `randomPerson` to `run.js` as follows: + +```js +const [owner, randomPerson1, randomPerson2] = await hre.ethers.getSigners(); +``` + +### 🙋‍♂️ Asking Questions + +If you have any questions about the work so far, please ask in Discord's `#ethereum` channel. + +To help the process of providing assistance flow smoothly, please include the following 3 points in your error report ✨ + +``` +1. Section number and lesson number related to the question +2. What you were trying to do +3. Copy & paste the error message +4. Screenshot of the error screen +``` + +--- + +In the next lesson, we'll deploy your smart contract to a test environment. Let's move on 🎉 diff --git a/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-5.md b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-5.md new file mode 100644 index 00000000..258ee697 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-1/lesson-5.md @@ -0,0 +1,150 @@ +--- +title: Deploy the Contract to Your Local Environment +--- +### 🐣 Deploy the Smart Contract in Your Local Environment + +Actually, every time we ran tests with `run.js`, the following was happening: + +1. Create a new Ethereum network in the local environment. + +2. Deploy the contract in the local environment. + +3. When the program ends, Hardhat automatically deletes that Ethereum network. + +In this lesson, you'll learn how to **keep** the Ethereum network alive in your local environment instead of deleting it. + +Create a **new** window in your terminal. + +Edit the `script` section of `packages/contract/package.json` as follows: + +```json + "scripts": { + "run:script": "npx hardhat run scripts/run.js", + "test": "npx hardhat test", + "deploy": "npx hardhat run scripts/deploy.js --network sepolia", + "start": "npx hardhat node" + }, +``` + +Now let's run the command below: + +``` +yarn contract start +``` + +This will start up an Ethereum network on your local network. + +Look at the output in your terminal and confirm that Hardhat has provided you with 20 accounts (`Account`) and that all of them have been given `10000 ETH`. + +We'll deploy the smart contract on this local network. + +Update `deploy.js` in the `scripts` directory as follows: + +- `deploy.js` will serve to connect your frontend that you'll build in the future with your smart contract (`WavePortal.sol`). + +- If `run.js` is a program for testing, `deploy.js` is for production. + +```js +const main = async () => { + const [deployer] = await hre.ethers.getSigners(); + const accountBalance = await deployer.getBalance(); + const waveContractFactory = await hre.ethers.getContractFactory("WavePortal"); + const waveContract = await waveContractFactory.deploy(); + const wavePortal = await waveContract.deployed(); + + console.log("Deploying contracts with account: ", deployer.address); + console.log("Account balance: ", accountBalance.toString()); + console.log("Contract deployed to: ", wavePortal.address); + console.log("Contract deployed by: ", deployer.address); +}; + +const runMain = async () => { + try { + await main(); + process.exit(0); + } catch (error) { + console.error(error); + process.exit(1); + } +}; + +runMain(); +``` + +The content of the code is almost the same as `run.js`. + +- `Account balance` is a string representing the balance (**wei**) allocated to your account. + +### 🎉 Let's Deploy + +Edit the `script` section of `packages/contract/package.json` as follows: + +```json + "scripts": { + "run:script": "npx hardhat run scripts/run.js", + "test": "npx hardhat test", + "deploy": "npx hardhat run scripts/deploy.js --network sepolia", + "deploy:localhost": "npx hardhat run scripts/deploy.js --network localhost", + "start": "npx hardhat node" + }, +``` + +**Open a new terminal window** and run the following command. This will deploy your smart contract to the local network: + +``` +yarn contract deploy:localhost +``` + +Did you see output like the following in your terminal? + +``` +Deploying contracts with account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +Account balance: 10000000000000000000000 +Contract deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +Contract deployed by: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +``` + +If results like the above are displayed in your terminal, the deployment is successful 🎉 + +Let's look at the output results in detail: + +``` +Deploying contracts with account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +``` + +Here, the address of the person who deployed the smart contract (= you in this case) is displayed. + +``` +Account balance: 10000000000000000000000 +``` + +The Account balance shows the default value of `10^22 wei` (= `10000 ETH`). + +- `Wei` is the smallest denomination of Ethereum. +- `1ETH = 1,000,000,000,000,000,000 wei (10^18)`. + +``` +Contract deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +``` + +Here, **the address where your smart contract was deployed** is displayed. + +### 🙋‍♂️ Asking Questions + +If you have any questions about the work so far, please ask in Discord's `#ethereum` channel. + +To help the process of providing assistance flow smoothly, please include the following 3 points in your error report ✨ + +``` +1. Section number and lesson number related to the question +2. What you were trying to do +3. Copy & paste the error message +4. Screenshot of the error screen +``` + +--- + +Congratulations! You've completed Section 1! +Post the output displayed in your terminal to `#ethereum` and celebrate your success with the community 🎉 +Let's move on to the next section! + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-2/lesson-1.md b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-2/lesson-1.md new file mode 100644 index 00000000..a93b6f37 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/Ethereum/ETH-dApp/section-2/lesson-1.md @@ -0,0 +1,275 @@ +--- +title: Deploy the Contract to the Testnet +--- +### 🖥 Building the Production Environment + +Let's terminate the local Ethereum network. + +- Just close the terminal and you're done. + +From now on, we'll build an environment for deploying contracts to an actual blockchain. + +### 🦊 Download MetaMask + +Next, let's download an Ethereum wallet. + +We'll use MetaMask for this project. + +- Download the browser extension from [here](https://MetaMask.io/download.html) and set up the MetaMask wallet in your browser. + +Even if you already have another wallet, please use MetaMask for this project. + +> ✍️: Why MetaMask is necessary +> When users call a smart contract, they need a wallet with their own Ethereum address and private key. +> This is like an authentication process. + +### 💳 Transactions + +**Writing new information to the blockchain on the Ethereum network** is called a **transaction**. + +The **transactions** that have appeared in the lessons so far are: + +- Write information to the blockchain that **a new smart contract has been deployed**. +- Write **the number of "👋 (waves)" sent on the website** to the blockchain. + +Since transactions require miner approval, we'll introduce Alchemy. + +Alchemy is a platform that centralizes transactions from around the world and facilitates miner approval. + +Create an Alchemy account from [here](https://www.alchemy.com/). + +### 💎 Create a Network on Alchemy + +Once you've created your Alchemy account, click the `+ Create new app` button on the Apps page. + +![](/images/ETH-dApp/section-2/2_1_1.png) + +Next, fill in the following items. Refer to the figure below: + +![](/images/ETH-dApp/section-2/2_1_2.png) + +- `Chain`: Select `Ethereum` +- `Network`: Select `Ethereum Sepolia` +- `Name`: Project name (e.g., `ETH dApp`) +- `Description`: Project overview (optional) + +When you click the `Create app` button, the project will be created. Click `API Key` to get the Key from the displayed popup (what we'll use for this project is what's shown in `HTTPS`). + +![](/images/ETH-dApp/section-2/2_1_3.png) + +This is the `API Key` you'll use when connecting to the production network. + +- **Save the `API Key` somewhere easy to find on your PC, as you'll need it later.** + +### 🐣 Starting with the Testnet + +For this project, we'll **deploy the contract to the testnet** instead of the Ethereum mainnet, which would incur costs (= real ETH). + +The testnet mimics the Ethereum mainnet. + +- It's ideal for testing events that occur when you deploy a contract to the Ethereum mainnet. +- Since the testnet uses fake ETH, you can test transactions as much as you want. + +This time, we'll be testing the following events: + +1. Notify miners around the world of a transaction occurrence +2. A certain miner discovers the transaction +3. That miner approves the transaction +4. That miner notifies other miners that the transaction has been approved and updates copies of the transaction + +In this section, we'll deepen our understanding of these events while writing code. + +### 🚰 Get Testnet ETH + +This time, we'll use a testnet called `Sepolia` operated by the Ethereum Foundation. + +Let's get fake ETH to deploy the contract to `Sepolia` and test the code. The infrastructure provided for users to get fake ETH is called a "faucet". + +Before using the faucet, set your MetaMask wallet to the `Sepolia Test Network`. + +> ✍️: How to set up `Sepolia Test Network` in MetaMask +> +> 1\. Open your MetaMask wallet's network toggle. +> +> ![](/images/ETH-dApp/section-2/2_1_4.png) +> +> 2\. Turn `Show test networks` to `ON` and select the displayed `Sepolia`. +> +> ![](/images/ETH-dApp/section-2/2_1_5.png) +> +> 3\. Confirm that the network has switched to `Sepolia`. +> +> ![](/images/ETH-dApp/section-2/2_1_6.png) + +Once the `Sepolia Test Network` is set up in your MetaMask wallet, select one from the links below that meets the conditions and get a small amount of fake ETH: + +- [Alchemy](https://sepoliafaucet.com/) - 1 Sepolia ETH (can be obtained once every 24 hours) + - Enter your wallet address and press the `Send Me ETH` button to receive it immediately. + +### 📈 Edit the `hardhat.config.js` File + +We need to modify the `hardhat.config.js` file. + +This is in the root directory of the smart contract project. + +- For this project, `hardhat.config.js` should exist directly under the `packages/contract` directory. + +Example: Result of moving to `packages/contract` in terminal and executing `ls` + +``` +$ ls +README.md artifacts cache contracts hardhat.config.js package.json scripts test +``` + +Open `hardhat.config.js` in VS Code and edit its contents: + +```js +require("@nomicfoundation/hardhat-toolbox"); + +module.exports = { + solidity: "0.8.19", + networks: { + sepolia: { + url: "YOUR_ALCHEMY_API_URL", + accounts: ["YOUR_PRIVATE_SEPOLIA_ACCOUNT_KEY"], + }, + }, +}; +``` + +1\. Getting `YOUR_ALCHEMY_API_URL` + +> Replace the `YOUR_ALCHEMY_API_URL` part of `hardhat.config.js` with the Alchemy URL (`HTTP` link) you obtained earlier. + +2\. Getting `YOUR_PRIVATE_SEPOLIA_ACCOUNT_KEY` + +> We'll obtain it by referring to the [documentation](https://support.metamask.io/hc/en-us/articles/360015289632). +> +> 1. From your browser, click the MetaMask plugin and click the account selection at the top of the screen. +> +> ![](/images/ETH-dApp/section-2/2_1_7.png) +> +> 2. Click the menu next to the account you want to export the private key for and open `Account details`. +> +> ![](/images/ETH-dApp/section-2/2_1_8.png) +> +> 3. Click `Show Private Key`. +> +> ![](/images/ETH-dApp/section-2/2_1_9.png) +> +> 4. You'll be asked for your MetaMask password, so enter it and press `Confirm`. +> +> ![](/images/ETH-dApp/section-2/2_1_10.png) +> +> 5. Press and hold `Hold to reveal Private Key` to display your private key (= `Private Key`), then click to copy it. +> +> ![](/images/ETH-dApp/section-2/2_1_11.png) + +> - Replace the `YOUR_PRIVATE_SEPOLIA_ACCOUNT_KEY` part of `hardhat.config.js` with the private key obtained here. + +### 🙊 Never Share Your Private Key with Anyone + +Once you've updated `hardhat.config.js`, let's pause here. + +**🚨: Do not commit the `hardhat.config.js` file to GitHub with your private key information included**. + +> This private key is the same as your Ethereum mainnet private key. +> +> If your private key is leaked, anyone can access your wallet, which is very dangerous. +> +> **Never place your private key where anyone other than yourself can see it**. + +Run the following to edit the `.gitignore` file in VS Code: + +``` +code .gitignore +``` + +Add a line for `hardhat.config.js` to `.gitignore`. + +If the contents of `.gitignore` look like the following, there's no problem: + +``` +node_modules +.env +coverage +coverage.json +typechain +typechain-types + +#Hardhat files +cache +artifacts +hardhat.config.js +``` + +Files and directories listed in `.gitignore` are not pushed to GitHub directories and are only stored in the local environment. + +> **✍️: Why a private key is needed to deploy a smart contract** +> **Deploying a new smart contract to the Ethereum network** is also a transaction. +> +> To make a transaction, you need to "log in" to the blockchain. +> +> "Logging in" requires the following information: +> +> - Username: Public address +> ![](/images/ETH-dApp/section-2/2_1_12.png) +> - Password: Private key +> ![](/images/ETH-dApp/section-2/2_1_13.png) +> It's the same as logging into AWS using a username and password to deploy a project. + +⚠️: What to do if you've already pushed `hardhat.config.js` to GitHub + +If you've already pushed code to GitHub, run the following in your terminal: + +``` +git rm --cached hardhat.config.js +``` + +This will delete the file from the remote repository while keeping the `hardhat.config.js` file in the local repository. After doing `git push` again, confirm that `hardhat.config.js` doesn't exist on GitHub. + +### 🚀 Deploy the Contract to Sepolia Test Network + +Once you've finished updating `hardhat.config.js`, let's try deploying the contract to the Sepolia Test Network. + +Make sure you're in the root directory and run the following command in your terminal: + +``` +yarn contract deploy +``` + +If results like the following are output, it's successful 🎉 + +``` +Deploying contracts with account: 0x1A7f14FBF50acf10bCC08466743fB90384Cbd720 +Account balance: 174646846389073382 +Contract deployed to: 0x04da168454AFA19Eb43D6A28b63964D8DCE8351e +Contract deployed by: 0x1A7f14FBF50acf10bCC08466743fB90384Cbd720 +``` + +On your terminal, copy and save the contract address (`0x..`) output after `Contract deployed to`. You'll need it later when building the frontend. + +### 👀 Check the Transaction on Etherscan + +Paste the address following the copied `Contract deployed to` into [Etherscan](https://sepolia.etherscan.io/) to see the transaction history of your smart contract. + +Etherscan is a convenient platform for checking information about transactions on the Ethereum network. + +_It may take about 1 minute to display._ + +### 🙋‍♂️ Asking Questions + +If you have any questions about the work so far, please ask in Discord's `#ethereum` channel. + +To help the process of providing assistance flow smoothly, please include the following 3 points in your error report ✨ + +``` +1. Section number and lesson number related to the question +2. What you were trying to do +3. Copy & paste the error message +4. Screenshot of the error screen +``` + +--- + +Once you've deployed your smart contract to the Sepolia Test Network, let's move on to the next lesson 🎉 diff --git a/scripts/prepare-translation.sh b/scripts/prepare-translation.sh new file mode 100755 index 00000000..8da161e4 --- /dev/null +++ b/scripts/prepare-translation.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +# prepare-translation.sh +# Helper script to prepare directory structure for translating a project + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to print colored output +print_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if project path is provided +if [ $# -eq 0 ]; then + print_error "No project path provided" + echo "Usage: $0 " + echo "Example: $0 docs/Ethereum/ETH-dApp" + exit 1 +fi + +PROJECT_PATH=$1 + +# Check if project path exists +if [ ! -d "$PROJECT_PATH" ]; then + print_error "Project path does not exist: $PROJECT_PATH" + exit 1 +fi + +# Extract relative path from docs/ +if [[ $PROJECT_PATH == docs/* ]]; then + REL_PATH=${PROJECT_PATH#docs/} +else + print_error "Project path must start with 'docs/'" + echo "Example: docs/Ethereum/ETH-dApp" + exit 1 +fi + +PROJECT_NAME=$(basename "$PROJECT_PATH") +TRANSLATION_BASE="i18n/en/docusaurus-plugin-content-docs/current" +TRANSLATION_PATH="$TRANSLATION_BASE/$REL_PATH" + +print_info "Project: $PROJECT_NAME" +print_info "Source: $PROJECT_PATH" +print_info "Target: $TRANSLATION_PATH" + +# Check if translation already exists +if [ -d "$TRANSLATION_PATH" ]; then + print_warning "Translation directory already exists: $TRANSLATION_PATH" + read -p "Do you want to continue? This might overwrite existing files. (y/N) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Aborted by user" + exit 0 + fi +fi + +# Create base directory structure +print_info "Creating directory structure..." +mkdir -p "$TRANSLATION_PATH" + +# Find all markdown files and create corresponding directory structure +while IFS= read -r -d '' file; do + # Get relative path from project root + rel_file="${file#$PROJECT_PATH/}" + dir_name=$(dirname "$rel_file") + + if [ "$dir_name" != "." ]; then + mkdir -p "$TRANSLATION_PATH/$dir_name" + print_info "Created directory: $TRANSLATION_PATH/$dir_name" + fi +done < <(find "$PROJECT_PATH" -name "*.md" -print0) + +# Count files +file_count=$(find "$PROJECT_PATH" -name "*.md" | wc -l) + +print_info "Directory structure created!" +print_info "Found $file_count markdown files to translate" +echo "" +print_info "Next steps:" +echo " 1. Translate each markdown file from:" +echo " $PROJECT_PATH/" +echo " to:" +echo " $TRANSLATION_PATH/" +echo "" +echo " 2. You can use AI tools (ChatGPT, Claude, DeepL) for translation" +echo " See docs/TRANSLATION_GUIDE.md for tips" +echo "" +echo " 3. Test your translation:" +echo " yarn start --locale en" +echo "" +echo " 4. Build to check for errors:" +echo " yarn build" +echo "" + +# List all files that need translation +echo "Files to translate:" +find "$PROJECT_PATH" -name "*.md" | sort | while read file; do + rel_file="${file#$PROJECT_PATH/}" + target_file="$TRANSLATION_PATH/$rel_file" + if [ -f "$target_file" ]; then + echo " [EXISTS] $rel_file" + else + echo " [ TODO ] $rel_file" + fi +done + +echo "" +print_info "Translation preparation complete! 🎉"