---
# System prepended metadata

title: 第一週作業
tags: [Solidity 工程師實戰營第 5 期]

---

# 第一週作業

## **1. 請簡單描述錢包助記詞，私鑰，公鑰之間的關係**

助記詞
拿來當作錢包的帳號，private key的一種表現方式，要注意不能外漏。
建議寫在紙上，不要用電腦截圖，或是手機拍照，以防被駭客偷走。
只要擁有助記詞，就等於擁有權力使用這個錢包。

私鑰
私鑰其實就是一串隨機數，具體而言，
以太坊的私鑰是一串隨機正整數，而這個值的區間位於 1 ~ 2²⁵⁶ — 1 之間，
也就是說，它是一串隨機生成的 256 bits 序列。這個 range 是非常巨大的，
要生成兩個一樣的私鑰是一件幾乎不可能會發生的事。
私鑰可以簽署交易，就像在現實生活中需要簽名才能夠轉帳一樣，
簽署過後的交易才能夠對你的帳戶資產進行更改。
只有擁有私鑰的人才能夠簽署這筆交易，交易才能被認可和被驗證。

公鑰
在 Ethereum 中，私鑰是用來將訊息簽名的，
而公鑰是用來驗證簽名的，所有人都可以獲取你的公鑰以驗證簽名。
Ethereum 的公鑰是由私鑰經過橢圓曲線演算法 ECDSA(Elliptic Curve Digital Signature Algorithm) 算出來的，
透過私鑰轉換成公鑰非常容易，但是要透過公鑰轉換成私鑰是一件非常困難的事

## **2. 用 Remix 部署智能合約(Local London)，將寫好的合約部署到 Görli / Goerli 測試鏈上，並 verify 開源程式碼**

合約地址：[0xF596AcDeB07aCd57FE79052c691B9854af5C7e2F](https://goerli.etherscan.io/address/0xf596acdeb07acd57fe79052c691b9854af5c7e2f)

```
/**
 *Submitted for verification at Etherscan.io on 2023-03-05
*/

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract TodoList {
    TodoStruct[] private todos; //代辦事項草稿區
    TodoStruct[] private pendings; // 代辦事項待送區
    TodoStruct[] private completeds; // 代辦事項已完成區
    uint256 private limitSec = 30; // Pending超過多少秒不給回ToDo

    //建構式
    constructor() {}

    //ToDo Object
    struct TodoStruct {
        string todoText; //代辦事項
        uint256 timestamp; //時間戳記
    }

    //Result Object
    struct ResultStruct {
        string code; //回傳代碼
        string desc; //回傳說明
    }

    // 永久儲存是storage，短暫使用就用memory，calldata傳入後只能參考不能改變的data type

    // =========== 代辦事項草稿區 =========== //
    // 新增代辦事項草稿文件
    function setTodo(string memory todo)
        external
        returns (ResultStruct memory)
    {
        todos.push(TodoStruct(todo, this.getTime()));
        return ResultStruct("0000", "Success");
    }

    // 取得所有代辦事項草稿文件
    function getTodos() external view returns (TodoStruct[] memory) {
        return todos;
    }

    // 取得代辦事項草稿文件 By index
    function getTodo(uint256 todosIndex)
        external
        view
        returns (TodoStruct memory)
    {
        return todos[todosIndex];
    }

    // 刪除代辦事項草稿文件
    function deleteTodos(uint256 todosIndex)
        external
        returns (ResultStruct memory)
    {
        if (!checkTodoStructIsNull(todos[todosIndex])) {
            deleteAndSortAndPop(todosIndex, "todos");
            return ResultStruct("0000", "Success");
        } else {
            return ResultStruct("0009", "TodoStruct Is Null");
        }
    }

    // =========== 代辦事項待送區 =========== //
    // 新增代辦事項待送文件
    function setPending(uint256 todosIndex)
        external
        returns (ResultStruct memory)
    {
        TodoStruct memory todo = this.getTodo(todosIndex); //取得代辦事項草稿區文件

        // 判斷該物件是否存在
        if (!checkTodoStructIsNull(todo)) {
            deleteAndSortAndPop(todosIndex, "todos");
            todo.timestamp = this.getTime();
            pendings.push(todo);
            return ResultStruct("0000", "Success");
        } else {
            return ResultStruct("0009", "TodoStruct Is Null");
        }
    }

    // 取得所有代辦事項待送文件
    function getAllPending() external view returns (TodoStruct[] memory) {
        return pendings;
    }

    // 取得代辦事項待送文件 By index
    function getPending(uint256 pendingsIndex)
        external
        view
        returns (TodoStruct memory)
    {
        return pendings[pendingsIndex];
    }

    // 代辦事項待送區文件 返回 代辦事項草稿區
    function pending2Todos(uint256 pendingsIndex)
        external
        returns (ResultStruct memory)
    {
        TodoStruct memory todo = this.getPending(pendingsIndex); //取得代辦事項草稿區文件

        // 判斷該物件是否存在
        if (!checkTodoStructIsNull(todo)) {
            //如果現在時間 - 物件儲存時間 <= 限制秒數，則可以退回todos
            if (this.getTime() - todo.timestamp <= limitSec) {
                deleteAndSortAndPop(pendingsIndex, "pendings");
                todo.timestamp = this.getTime();
                todos.push(todo);
                return ResultStruct("0000", "Success");
            } else {
                return ResultStruct("0001", "time expired");
            }
        }

        return ResultStruct("0009", "TodoStruct Is Null");
    }

    // 刪除代辦事項待送區文件
    function deletePending(uint256 pendingsIndex)
        external
        returns (ResultStruct memory)
    {
        TodoStruct memory todo = this.getPending(pendingsIndex); //取得代辦事項待送區文件

        // 判斷該物件是否存在
        if (!checkTodoStructIsNull(todo)) {
            deleteAndSortAndPop(pendingsIndex, "pendings");
            return ResultStruct("0000", "Success");
        } else {
            return ResultStruct("0009", "TodoStruct Is Null");
        }
    }

    // =========== 代辦事項完成區 =========== //

    // 新增代辦事項完成區文件
    function setCompleted(uint256 pendingsIndex)
        external
        returns (ResultStruct memory)
    {
        TodoStruct memory todo = this.getPending(pendingsIndex); //取得代辦事項待送區文件

        // 判斷該物件是否存在
        if (!checkTodoStructIsNull(todo)) {
            deleteAndSortAndPop(pendingsIndex, "pendings");
            todo.timestamp = this.getTime();
            completeds.push(todo);
            return ResultStruct("0000", "Success");
        } else {
            return ResultStruct("0009", "TodoStruct Is Null");
        }
    }

    // 取得代辦事項完成區文件 By index
    function getCompleted(uint256 completedIndex)
        external
        view
        returns (TodoStruct memory)
    {
        return completeds[completedIndex];
    }

    // 取得所有代辦事項完成區文件
    function getAllCompleted() external view returns (TodoStruct[] memory) {
        return completeds;
    }

    function deleteAllCompleteds() external returns (ResultStruct memory) {
        delete completeds;
        return ResultStruct("0000", "Success");
    }

    // =========== 其他 =========== //
    // 判斷 Struct 是否為 null
    function checkTodoStructIsNull(TodoStruct memory todo)
        private
        pure
        returns (bool)
    {
        if (bytes(todo.todoText).length == 0 && todo.timestamp == 0) {
            return true;
        } else {
            return false;
        }
    }

    // Array delete Todo And Sort And pop
    function deleteAndSortAndPop(uint256 index, string memory arrStr) private {
        TodoStruct[] storage arr = todos;

        if (
            bytes(arrStr).length == bytes("pendings").length &&
            keccak256(abi.encode(arrStr)) == keccak256(abi.encode("pendings"))
        ) {
            arr = pendings;
        } else if (
            bytes(arrStr).length == bytes("completeds").length &&
            keccak256(abi.encode(arrStr)) == keccak256(abi.encode("completeds"))
        ) {
            arr = completeds;
        }

        if (arr.length > 0) {
            // 把index後面的全部替代前一格
            for (uint256 i = index; i < arr.length - 1; i++) {
                arr[i] = arr[i + 1];
            }

            delete arr[arr.length - 1]; //刪除最後一格的資料
            arr.pop(); //移除陣列最後一格的空間，這樣可以減少gas
        }
    }

    //設定 Pending超過多少秒不給回ToDo 的限制秒數
    function setLimitSec(uint256 sec) external {
        limitSec = sec;
    }

    //取得現在時間
    function getTime() external view returns (uint256) {
        return block.timestamp;
    }
}
```

###### tags: `Solidity 工程師實戰營第 5 期`