# Day2. 使用 javascript 建構 DAO

By [Samumu.eth](https://paragraph.com/@samumu) · 2022-02-26

---

經過[上一篇教程](https://mirror.xyz/samumu.eth/8fiP-eUnzGeJ7TLRz36G9B8UwX6pSOxscHpYYbQSRJc)，我們現在可以連接到使用者的錢包，這意味著我們現在可以驗證該用戶是否在我們的DAO中。為了加入我們的DAO，使用者將需要一個會員資格NFT，如果他們沒有會員資格NFT，我們會提示他們是否鑄造會員NFT並加入我們的DAO（你也可以自己設計一個比較好的機制，比如常見的白單限制）

要完成以上的需求，我們需要編寫+部署我們自己的NFT智能合約，在這邊我們使用ThirdWeb給我們提供的是一套工具，可以在不編寫任何Solidity的情況下創建我們所有的智能合約（不過使用這種方式會有諸多局限性，如果你對於Solidity很熟悉，之後也可以嘗試自己編寫並部署）

不過我們這系列的都不會使用到Solidity編碼，ThirdWeb提供了[一組安全的合同標準](https://github.com/thirdweb-dev/contracts)，並且在部署之後你也可以使用其用戶端 SDK 輕鬆地從前端與這些合約進行交互

介紹完我們接下來要使用的強力工具，我們可以開嚕了

### 創建 ThirdWeb 專案

到[此網站](https://thirdweb.com/dashboard)創建專案

1.  連接含有 Rinkeby ETH 的 Metamask address（部署合約時會需要耗費gas fee）
    
2.  連接到 Rinkeby 網路
    
3.  點擊右上 Create Project（這將為我們將在鏈上部署的合約創建容器，**thirdweb不會有中心化資料庫，你的所有數據都存儲在鏈上**）
    
4.    
    

### 獲取 Alchemy API

到[Alchemy官網](https://dashboard.alchemyapi.io/)申請帳號，並點擊 `+CREATE APP` 來創建，NETWORK部分一定要選擇到Rinkeby，創建完成後，點擊 `VIEW KEY` 可以看到你的 `API KEY` , `HTTP` , `WEBSOCKETS`

![](https://storage.googleapis.com/papyrus_images/71b91a13f20d2097fe10e39608de821924a1c6e8a952960d34514ca4d2da7b48.png)

### .ENV存儲私鑰

現在，我們需要實際編寫一些腳本，讓我們使用thirdweb創建/部署我們的合約到Rinkeby。首先，我們要做的第一件事是在專案的根目錄中創建一個`.env` 檔

    PRIVATE_KEY=YOUR_PRIVATE_KEY_HERE
    WALLET_ADDRESS=YOUR_WALLET_ADDRESS
    ALCHEMY_API_URL=YOUR_ALCHEMY_API_URL
    

thirdweb需要所有這些東西來代表你部署合同，它們不存儲任何內容，所有內容都保留在本地的檔中。**謹記不要將** `.env` 檔提交到 Github，你的錢包會被搶劫的，小心！！！

> 從Metamask獲取所需資訊

點擊【Account details】，再點擊【Export Private Key】，輸入密碼後便可取得 `PRIVATE_KEY`

點擊Account下方 `0x...` 後方的複製icon即可取得 `WALLET_ADDRESS`

> 從Alchemy獲取 `ALCHEMY_API_URL`

![](https://storage.googleapis.com/papyrus_images/ef92975f4a0407e80d77ce49d14d7ef730f1eb292c3f544f61793b8eb6dfdf18.png)

![](https://storage.googleapis.com/papyrus_images/027f43dae222d7d520115c515440549c3783643cc6011c74b35135bdd16b8036.png)

**初始化軟體開發工具組**

前往 .`scripts/1-initialize-sdk.js`

    import { ThirdwebSDK } from "@3rdweb/sdk";
    import ethers from "ethers";
    
    import dotenv from "dotenv";
    dotenv.config();
    
    if (!process.env.PRIVATE_KEY || process.env.PRIVATE_KEY == "") {
      console.log("🛑 Private key not found.")
    }
    
    if (!process.env.ALCHEMY_API_URL || process.env.ALCHEMY_API_URL == "") {
      console.log("🛑 Alchemy API URL not found.")
    }
    
    if (!process.env.WALLET_ADDRESS || process.env.WALLET_ADDRESS == "") {
      console.log("🛑 Wallet Address not found.")
    }
    
    const sdk = new ThirdwebSDK(
      new ethers.Wallet(
        process.env.PRIVATE_KEY,
        ethers.getDefaultProvider(process.env.ALCHEMY_API_URL),
      ),
    );
    
    (async () => {
      try {
        const apps = await sdk.getApps();
        console.log("Your app address is:", apps[0].address);
      } catch (err) {
        console.error("Failed to get apps from the sdk", err);
        process.exit(1);
      }
    })()
    
    export default sdk;
    

我們這邊所做的是初始化thirdweb，然後添加一個third web SDK，因為我們將在其他腳本中重用初始化的sdk。在初始化的過程中我們必須提供 `PRIVATE_KEY`以及使用 `ALCHEMY_API_URL` 創建的 prvider

在執行該腳本之前，請確保您安裝了Node 16 +，您可以使用以下命令檢查您的版本：

    node -v
    

如果您有舊版本的 Node，可以[在此處](https://nodejs.org/en/)進行更新。（下載 LTS 版本）

接下來，讓我們來執行這個腳本，移至終端並貼下以下命令：

    node scripts/1-initialize-sdk.js
    

以下是運行完腳本時獲得的內容

    buildspace-dao-starter % node scripts/1-initialize-sdk.js
    👋 Your app address is: 0xa002D595189bF9D50D5897C64b6e07BE5bdEe9b8
    

💡 \*注意：您可能還會看到一些隨機警告，例如\*\`ExperimentalWarning\`，只需確保您的應用程式位址已列印出來即可！

接著將這段地址加入 `.env` 檔，你目前的 `.env` 檔內應該如下：

    PRIVATE_KEY=<YOUR_PRIVATE_KEY_HERE>
    ALCHEMY_API_URL=<YOUR_ALCHEMY_API_URL>
    WALLET_ADDRESS=<YOUR_WALLET_ADDRESS>
    
    APP_MODULE_ADDRESS=0xa002D595189bF9D50D5897C64b6e07BE5bdEe9b8
    

### 創建 ERC1155 集合

我們現在要做的是創建+部署ERC1155合約到Rinkeby，這是我們創建NFT所需的基本模組。這邊我們要先為NFT設置元數據\*\*。\*\*這是諸如集合的名稱（例如CryptoPunks）以及與集合關聯的圖像之類的東西，該圖像在OpenSea上顯示為標題。

💡 您可能知道ERC-721，其中每個NFT都是唯一的，即使它們具有相同的圖像，名稱和屬性。使用ERC-1155，多個人可以成為同一NFT的持有者。在這種情況下，我們的"會員NFT"對每個人都是一樣的，因此，與其每次都製作一個新的NFT，我們可以簡單地將相同的NFT分配給所有會員。

移至並新增以下代碼：`scripts/2-deploy-drop.js`

    import { ethers } from "ethers";
    import sdk from "./1-initialize-sdk.js";
    import { readFileSync } from "fs";
    
    import dotenv from "dotenv";
    dotenv.config();
    
    const app = sdk.getAppModule(process.env.APP_MODULE_ADDRESS);
    
    (async () => {
      try {
        const bundleDropModule = await app.deployBundleDropModule({
          name: "DevDAO",
          description: "A DAO for devloper",
          image: readFileSync("scripts/assets/dev.png"),
          primarySaleRecipientAddress: ethers.constants.AddressZero,
        });
    
        console.log(
          "✅ Successfully deployed bundleDrop module, address:",
          bundleDropModule.address,
        );
        console.log(
          "✅ bundleDrop metadata:",
          await bundleDropModule.getMetadata(),
        );
      } catch (error) {
        console.log("failed to deploy bundleDrop module", error);
      }
    })()
    

我們給集合一個`name`、`description`、 `primarySaleRecipientAddress` 和 `image`

*   name: DAO 的名稱，請自己隨意命名
    
*   description: 簡單描述這個 DAO
    
*   image: 我們會從本地檔載入，因此請確保將該圖像包含在下`scripts/assets` ，並確保圖片格式是PNG，JPG或GIF
    
*   primarySaleRecipientAddress: 傳入一個地址，這個地址是用來接收NFT賣出的$，這邊我們將其設定為 ‘0x0’ 也就是 `ethers.constants.AddressZero` 是為了不向使用者收費，你也可以將地址改為自己的地址來收費
    

運行此腳本後會看到如下輸出：

    node scripts/2-deploy-drop.js
    

    buildspace-dao-starter % node scripts/2-deploy-drop.js
    👋 Your app address is: 0xa002D595189bF9D50D5897C64b6e07BE5bdEe9b8
    ✅ Successfully deployed bundleDrop module, address: 0x31c70F45060AE0870624Dd9D79A1d8dafC095A5d
    ✅ bundleDrop metadata: {
      metadata: {
        name: 'NarutoDAO Membership',
        description: 'A DAO for fans of Naruto.',
        image: 'https://cloudflare-ipfs.com/ipfs/bafybeicuuhilocc2tskhnvbwjqarsc5k7flfqdr4ifvwxct32vzjmb3sam',
        primary_sale_recipient_address: '0x0000000000000000000000000000000000000000',
        uri: 'ipfs://bafkreieti3mpdd3pytt3v6vxbc3rki2ja6qpbblfznmup2tnw5mghrihnu'
      },
      address: '0x31c70F45060AE0870624Dd9D79A1d8dafC095A5d',
      type: 11
    }
    

首先，我們剛剛向Rinkeby部署了[ERC-1155](https://docs.openzeppelin.com/contracts/3.x/erc1155)合同，如果你到[etherscan](https://rinkeby.etherscan.io/)並查詢 `bundleDrop` 的地址（第一行的地址），會發現你成功剛剛部署了一個智能合約！

把這串地址添加到 `.env` 檔

    PRIVATE_KEY=<YOUR_PRIVATE_KEY_HERE>
    ALCHEMY_API_URL=<YOUR_ALCHEMY_API_URL>
    WALLET_ADDRESS=<YOUR_WALLET_ADDRESS>
    
    APP_MODULE_ADDRESS=0xa002D595189bF9D50D5897C64b6e07BE5bdEe9b8
    BUNDLEDROP_MODULE_ADDRESS=0xa002D595189bF9D50D5897C64b6e07BE5bdEe9b8
    

![](https://storage.googleapis.com/papyrus_images/d639c063594dc8c47f9a0a8798708b2dcbb01ce62c01bc84b4d22ed4643df0e0.png)

可以[在此處](https://github.com/nftlabs/nftlabs-protocols/blob/main/contracts/LazyNFT.sol)查看thirdweb使用的實際智慧合約代碼

另外，我們可以通過[CloudFlare](https://cloudflare-ipfs.com)從IPFS檢索NFT的圖像

您甚至可以使用URI直接點擊IPFS（注意 - 由於您需要運行IPFS節點，因此在Chrome上不起作用，但可以在Brave上工作，它可以為您做到這一點

💡 IPFS基本上是一個分散的存儲系統，\[請在此處閱讀更多內容\](https://docs.ipfs.io/concepts/what-is-ipfs/)！

如果您之前在Solidity中開發了一個自定義智慧合約，也了解其開發過程，相對來說，使用thirdWeb 讓整個流程變得更簡單，目前，我們已經有一個合約部署到IPFS上託管的Rinkeby +數據，恭喜你

接下來，我們需要實際創建我們的NFT [Day3. 使用 javascript 建構 DAO](https://www.notion.so/Day3-javascript-DAO-5ccc27d91587479dbd6adb93d9189091)

---

*Originally published on [Samumu.eth](https://paragraph.com/@samumu/day2-javascript-dao)*
