自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

在以太坊上構(gòu)建去中心化的待辦事項(xiàng)列表應(yīng)用程序

區(qū)塊鏈
我們將涵蓋有趣的主題,例如設(shè)置開發(fā)環(huán)境、編寫 Solidity 智能合約、測(cè)試它以及將其部署到 Sepolia 測(cè)試網(wǎng)。一起編寫代碼以便更好地理解!

歡迎來(lái)到以太坊區(qū)塊鏈上令人興奮的去中心化應(yīng)用程序 (dApp) 世界!在本分步指南中,我們將逐步介紹使用 Hardhat 開發(fā)框架創(chuàng)建去中心化待辦事項(xiàng)列表應(yīng)用程序的過(guò)程。

我們將涵蓋有趣的主題,例如設(shè)置開發(fā)環(huán)境、編寫 Solidity 智能合約、測(cè)試它以及將其部署到 Sepolia 測(cè)試網(wǎng)。一起編寫代碼以便更好地理解!

先決條件

在我們深入研究之前,請(qǐng)確保您擁有以下工具和先決條件:

  • ? Node
  • ? Hardhat:與區(qū)塊鏈交互的 JavaScript 框架。
  • ? Metamask:安裝 Metamaks 并獲取您的私鑰。配置 Metamask 以連接到 Sepolia 網(wǎng)絡(luò)。
  • ? Alchemy:獲取 Sepolia 測(cè)試網(wǎng)的 Alchemy HTTP 端點(diǎn)。這是有關(guān)如何設(shè)置的指南。[1]
  • ? Test Sepolia ETH:從水龍頭[2]請(qǐng)求一些Sepolia ETH 。

設(shè)置我們的環(huán)境

現(xiàn)在我們已經(jīng)收集了我們的工具,是時(shí)候設(shè)置我們的開發(fā)環(huán)境了。

這是分步指南:

? 為您的應(yīng)用程序 todolist 創(chuàng)建一個(gè)新的項(xiàng)目目錄。

mkdir todolist
cd todolist
npm init -y
npm install --save-dev hardhat

? 通過(guò)運(yùn)行以下命令來(lái)初始化您的 Hardhat 項(xiàng)目:

npx hardhat init
  • 選擇創(chuàng)建 JavaScript 項(xiàng)目的選項(xiàng),并接受默認(rèn)選項(xiàng)。Hardhat 將生成一個(gè)示例項(xiàng)目并為您安裝必要的依賴項(xiàng)。
  • ? 在您喜歡的代碼編輯器中打開您的項(xiàng)目文件夾。如果您使用 Visual Studio Code,只需運(yùn)行:
code .

? 為了確保 Metamask 私鑰和 Alchemy RPC URL 等敏感信息的安全,請(qǐng)?jiān)陧?xiàng)目目錄中創(chuàng)建一個(gè) .env 文件,并按以下格式存儲(chǔ)密鑰:

圖片圖片

? 安裝該dotenv軟件包,這將幫助我們使用環(huán)境變量:

npm i dotenv

? 修改 Hardhat 配置文件(通常名為 Hardhat.config.js)以識(shí)別文件中的密鑰.env:

require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();

module.exports = {
  solidity: "0.8.19",

  networks: {
    sepolia: {
      url: process.env.ALCHEMY_API_KEY_URL,
      accounts: [process.env.PRIVATE_KEY],
    },
  },
};

您的環(huán)境現(xiàn)在已準(zhǔn)備好在以太坊區(qū)塊鏈上施展魔法!

建立我們的合同

讓我們通過(guò)編寫 Solidity 智能合約來(lái)深入研究待辦事項(xiàng)列表應(yīng)用程序的核心。在合同文件夾中,您將找到默認(rèn)的“Lock.sol”文件。首先在“contracts”文件夾中找到“Lock.sol”文件,并將其重命名為“TodoList.sol”以與我們的合約名稱保持一致。

下面是“TodoList”合約,以及解釋每個(gè)代碼塊的作用的注釋:

// SPDX-License-Identifier: MIT

// Solidity Version
pragma solidity 0.8.19;

contract TodoList {
    // Struct to represent a task
    struct Task {
        uint id; // Unique task identifier
        uint date; // Timestamp of task creation
        string name; // Task name
        string description; // Task description
        bool isCompleted; // Flag indicating task completion status
        address owner; // Address of the task owner
    }

    // Array to store all tasks
    Task[] public tasks;

    // Mapping to associate user addresses with their task IDs
    mapping(address => uint[]) private userTasks;

    // Constructor function
    constructor() {}

    // Event emitted when a task is created
    event TaskCreated(
        uint id,
        uint date,
        string name,
        string description,
        bool isCompleted,
        address owner
    );

    // Event emitted when a task is marked as completed
    event TaskCompleted(uint id, address owner);

    // Event emitted when a task is deleted
    event TaskDeleted(uint id, address owner);

    // Function to create a new task
    function createTask(string memory name, string memory description) public {
        uint taskId = tasks.length; // Calculate the new task ID
        tasks.push(
            Task(taskId, block.timestamp, name, description, false, msg.sender)
        ); // Create and add the new task to the array
        userTasks[msg.sender].push(taskId); // Update the userTasks mapping
        emit TaskCreated(
            taskId,
            block.timestamp,
            name,
            description,
            false,
            msg.sender
        ); // Emit a TaskCreated event
    }

    // Function to retrieve task details by ID
    function getTask(
        uint id
    )
        public
        view
        returns (uint, uint, string memory, string memory, bool, address)
    {
        // Ensure the task ID is valid
        require(id < tasks.length, "Task ID does not exist"); 
        Task storage task = tasks[id]; // Retrieve the task from storage
        return (
            task.id,
            task.date,
            task.name,
            task.description,
            task.isCompleted,
            task.owner
        ); // Return task details
    }

    // Function to mark a task as completed
    function markTaskCompleted(uint id) public {
        // Ensure the task ID is valid
        require(id < tasks.length, "Task ID does not exist"); 
        Task storage task = tasks[id]; // Retrieve the task from storage
        require(
            task.owner == msg.sender,
            "Only the owner can complete the task"
        );
        // Ensure the task is not already completed
        require(!task.isCompleted, "Task is already completed"); 
        task.isCompleted = true; // Mark the task as completed
        emit TaskCompleted(id, msg.sender); // Emit a TaskCompleted event
    }

    // Function to delete a task
    function deleteTask(uint id) public {
        // Ensure the task ID is valid
        require(id < tasks.length, "Task ID does not exist"); 
        Task storage task = tasks[id]; // Retrieve the task from storage
        // Ensure only the owner can delete the task
        require(task.owner == msg.sender, "Only the owner can delete the task"); 
        emit TaskDeleted(id, msg.sender); // Emit a TaskDeleted event

        // Delete the task by replacing it with the last task in the array 
        // and reducing the array size
        uint lastIndex = tasks.length - 1;
        if (id != lastIndex) {
            Task storage lastTask = tasks[lastIndex];
            tasks[id] = lastTask;
            userTasks[msg.sender][id] = lastIndex;
        }
        tasks.pop();
        userTasks[msg.sender].pop();
    }

    // Function to retrieve all task IDs belonging to the caller
    function getUserTasks() public view returns (uint[] memory) {
        // Return the task IDs associated with the caller's address
        return userTasks[msg.sender]; 
    }
}

測(cè)試我們的合約

測(cè)試我們的合約對(duì)于保證其可靠性和功能性以及確保其按預(yù)期執(zhí)行至關(guān)重要。在一個(gè)容易遭受黑客攻擊和漏洞利用的行業(yè)中,編寫測(cè)試非常有必要,以確保我們的合約不會(huì)容易受到漏洞利用。

用 Mocha 編寫我們的測(cè)試

我們將使用 Mocha 進(jìn)行測(cè)試,所以讓我們?cè)O(shè)置我們的測(cè)試。在 test 文件夾中,將 Lock.js 文件重命名為 test.js 并將代碼替換為以下內(nèi)容:

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("TodoList contract", function () {
  let TodoList;
  let todolist;
  let owner;

  before(async function () {
    [owner] = await ethers.getSigners();

    // Deploy the TodoList contract
    todolist = await ethers.deployContract("TodoList");
    // await TodoList.waitForDeployment();
  });

  it("should create a new task", async function () {
    const taskName = "Sample Task";
    const taskDescription = "This is a sample task description";

    // Create a new task
    await todolist.createTask(taskName, taskDescription);

    // Retrieve the task details
    const [id, date, name, description, isCompleted, taskOwner] =
      await todolist.getTask(0);

    expect(id).to.equal(0);
    expect(name).to.equal(taskName);
    expect(description).to.equal(taskDescription);
    expect(isCompleted).to.equal(false);
    expect(taskOwner).to.equal(owner.address);
  });

  it("should mark a task as completed", async function () {
    // Mark the task at index 0 as completed
    await todolist.markTaskCompleted(0);

    // Retrieve the task details
    const [, , , , isCompleted] = await todolist.getTask(0);

    expect(isCompleted).to.equal(true);
  });

  it("should delete a task", async function () {
    // Create a new task
    await todolist.createTask(
      "Task to be deleted",
      "This task will be deleted"
    );

    // Delete the task at index 1
    await todolist.deleteTask(1);

    // Attempt to retrieve the deleted task (should throw an error)
    let errorOccurred = false;
    try {
      await todolist.getTask(1);
    } catch (error) {
      errorOccurred = true;
    }

    expect(errorOccurred).to.equal(true);
  });

  it("should retrieve the user's tasks", async function () {
    // Create a new task
    await todolist.createTask("User's Task", "This is the user's task");

    // Retrieve the user's tasks
    const userTasks = await todolist.getUserTasks();

    // Expect that there is at least one task
    expect(userTasks.length).to.be.at.least(1);
  });
});

為了測(cè)試我們的合約,我們運(yùn)行通用的:

npx hardhat test

響應(yīng)應(yīng)如下所示:

圖片圖片

部署我們的合約

現(xiàn)在,令人興奮的部分 - 將我們的智能合約部署到 Sepolia 網(wǎng)絡(luò)。我們將編寫一個(gè)部署腳本來(lái)實(shí)現(xiàn)這一點(diǎn)。

編寫我們的部署腳本

在腳本文件夾中,您將找到一個(gè)包含一些示例代碼的deploy.js 文件。將 JavaScript 代碼替換為以下內(nèi)容:

// Import the ethers library from the Hardhat framework
const { ethers } = require("hardhat");

// Define an asynchronous main function for contract deployment
async function main() {
  // Deploy the contract
  const TodoList = await ethers.deployContract("TodoList");

  // Log message to show deployment in progress
  console.log("Deploying contract.....");

  // Wait for the deployment of the contract to complete
  await TodoList.waitForDeployment();

  // Log the deployment target (contract address) to the console
  console.log(`TodoList deployed to ${TodoList.target}`);
}

// Execute the main function, and handle any errors that may occur
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

要將我們的合約部署到 Sepolia 網(wǎng)絡(luò),請(qǐng)使用以下命令:

npx hardhat run scripts/deploy.js --network sepolia

注意:如果您打算將智能合約部署到不同的網(wǎng)絡(luò),您可以輕松替換 sepolia 為您選擇的網(wǎng)絡(luò)。

當(dāng)我們部署到測(cè)試網(wǎng)時(shí),這應(yīng)該需要幾秒鐘的時(shí)間。您將收到合同部署的確認(rèn)信息以及合同地址。

圖片圖片

img

現(xiàn)在您可以體驗(yàn)去中心化待辦事項(xiàng)列表變?yōu)楝F(xiàn)實(shí)的興奮!繼續(xù)復(fù)制您的合約地址并驗(yàn)證其在Sepolia Testnet Explorer[3]上的存在,就像您在以太坊主網(wǎng)上所做的那樣。超級(jí)有趣!

結(jié)論

您已成功構(gòu)建第一個(gè) dApp 并將其部署到以太坊區(qū)塊鏈。作為下一步,我強(qiáng)烈推薦以下資源:

Lumos Academy[4]:Lumos Labs 的 Lumos Academy 是一個(gè)專門為正在學(xué)習(xí) Web3 開發(fā)的(有抱負(fù)的)Web3 開發(fā)人員提供的平臺(tái)

以太坊開發(fā)教程[5]:這個(gè)精選的社區(qū)教程列表涵蓋了廣泛的以太坊開發(fā)主題

希望您喜歡這篇文章!如果您有任何問題或意見,請(qǐng)隨時(shí)在下面留言或在Twitter 上與我聯(lián)系![6]

原文:https://tosynthegeek.hashnode.dev/building-a-decentralized-todo-list-application-on-ethereum

引用鏈接

[1] 指南。: https://docs.alchemy.com/docs/how-to-add-alchemy-rpc-endpoint-for-local-development#step-2-add-http-url-to-local-project

[2] 水龍頭: https://sepoliafaucet.com/

[3] Sepolia Testnet Explorer: https://sepolia.etherscan.io/

[4] Lumos Academy: https://academy.lumoslabs.co/

[5] 以太坊開發(fā)教程: https://ethereum.org/en/developers/tutorials/[6] Twitter 上與我聯(lián)系!: https://twitter.com/tosynthegeek

責(zé)任編輯:武曉燕 來(lái)源: 李留白
相關(guān)推薦

2023-07-14 12:07:19

2019-02-21 09:40:22

開源工具待辦事項(xiàng)

2022-03-10 14:14:12

比特幣以太坊去中心化

2020-03-04 12:55:13

Emacs待辦事項(xiàng)應(yīng)用

2021-05-07 09:06:55

GraphQLAPI 以太坊

2021-04-26 15:10:41

比特幣DeFi金融

2024-03-27 11:18:02

2011-11-23 10:06:32

Azure微軟移動(dòng)應(yīng)用

2022-06-21 11:23:15

API鴻蒙JS開發(fā)

2019-12-19 14:17:11

以太坊去中心化加密貨幣

2023-11-06 09:06:05

2015-03-10 09:51:56

云開發(fā)云應(yīng)用程構(gòu)建PaaS

2015-10-14 10:43:17

PaaSSaaS應(yīng)用構(gòu)建

2011-03-14 14:47:50

2020-03-25 13:59:22

前端開發(fā)編程

2010-11-09 10:37:21

2021-06-17 08:22:45

PythonDeFi編程語(yǔ)言

2012-02-20 10:51:21

Clear待辦事項(xiàng)工具

2011-10-12 11:24:44

AndroidPC

2016-09-18 16:16:39

Linux云服務(wù)應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)