# Alchemy Road to Web3     第二周NFT获取教程

By [ChiefDavid](https://paragraph.com/@chiefdavid) · 2022-10-25

---

2019年12月，Alchemy完成**1500万美元A轮融资**，资方为Pantera Capital，斯坦福大学，Coinbase，三星等。

2021年4月，Alchemy以5.05亿美元估值完成**8000万美元B轮融资**，Coatue和Addition领投，DFJ Growth、K5 Global、Chainsmokers（烟鬼组合）、演员Jared Leto和Glazer家族参投。

2021年10月，Alchemy以35亿美元估值完成**2.5亿美元C轮融资**，由a16z领投的。

2022年2月，Alchemy以102亿美元估值完成**2亿美元融资**，Lightspeed与Silver Lake领投。

**Alchemy是一个**背景强大、经费充足、踏实做事、没有发币的团队，这样的项目不刷，难道去刷土狗吗？

并且，Alchemy计划将新资金用于推广Web3采用，这方面的一些举措包括推出Web3 University，就是现在的 Road to Web3 活动，活动为期10周，每周一个NFT。看了下nft数量极少，估计由于任务难度大，很多小伙伴直接放弃，这样的项目若是空投，绝对是大毛。

手把手第二周教程开始：如何构建“给我买杯咖啡”的 DeFi dapp
----------------------------------

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

官方原版[教程链接](https://docs.alchemy.com/docs/how-to-build-buy-me-a-coffee-defi-dapp)，其中有长达1小时30分钟的视频教程还有大篇幅的文字教程，并且有错误。我按照我的做法给大家一个易于操作的图文教程。

### step1 安装环境

1.[2022最新Nodejs下载安装配置步骤（保姆级教程）](https://blog.csdn.net/Lancelot38/article/details/125887397)

先按照上述教程安装Nodejs，共分为5步，前3步做完就正常了，我没有做第4和第5步，不放心可以做一下。最新版本号如下：

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

2.[VScode安装教程（超详细版）](https://blog.csdn.net/weixin_58068749/article/details/123635089)

再按照这个教程安装VScode。

### step2 对 BuyMeACoffee.sol 智能合约进行编码

1.按win+R调出命令框，输入cmd，进入控制台。

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

2.输入mkdir BuyMeACoffee-contracts按回车创建文件夹，再输入cd BuyMeACoffee-contracts 按回车进入该文件夹。

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

3.输入npm init -y 开始新项目。

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

4.输入npx hardhat创建示例项目。

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

5.之后连按三下回车，出现下图。

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

6.按照提示输入下面代码，坐等安装完毕。出现警告不管。

npm install --save-dev "hardhat@^2.10.1" "@nomicfoundation/hardhat-toolbox@^1.0.1"

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

7.打开vscode，点击file，点击open folder。

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

8.找到刚才创建的BuyMeACoffee-contracts文件夹，点击选择文件夹。

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

9.打开后如图所示。

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

10.右键rename将合约文件lock.sol重命名为 `BuyMeACoffee.sol`

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

11.`BuyMeACoffee.sol`代码替换成下面的并保存！（不保存没用啊，要点保存）

    //SPDX-License-Identifier: Unlicense
    
    // contracts/BuyMeACoffee.sol
    pragma solidity ^0.8.0;
    
    // Switch this to your own contract address once deployed, for bookkeeping!
    // Example Contract Address on Goerli: 0xDBa03676a2fBb6711CB652beF5B7416A53c1421D
    
    contract BuyMeACoffee {
        // Event to emit when a Memo is created.
        event NewMemo(
            address indexed from,
            uint256 timestamp,
            string name,
            string message
        );
        
        // Memo struct.
        struct Memo {
            address from;
            uint256 timestamp;
            string name;
            string message;
        }
        
        // Address of contract deployer. Marked payable so that
        // we can withdraw to this address later.
        address payable owner;
    
        // List of all memos received from coffee purchases.
        Memo[] memos;
    
        constructor() {
            // Store the address of the deployer as a payable address.
            // When we withdraw funds, we'll withdraw here.
            owner = payable(msg.sender);
        }
    
        /**
         * @dev fetches all stored memos
         */
        function getMemos() public view returns (Memo[] memory) {
            return memos;
        }
    
        /**
         * @dev buy a coffee for owner (sends an ETH tip and leaves a memo)
         * @param _name name of the coffee purchaser
         * @param _message a nice message from the purchaser
         */
        function buyCoffee(string memory _name, string memory _message) public payable {
            // Must accept more than 0 ETH for a coffee.
            require(msg.value > 0, "can't buy coffee for free!");
    
            // Add the memo to storage!
            memos.push(Memo(
                msg.sender,
                block.timestamp,
                _name,
                _message
            ));
    
            // Emit a NewMemo event with details about the memo.
            emit NewMemo(
                msg.sender,
                block.timestamp,
                _name,
                _message
            );
        }
    
        /**
         * @dev send the entire balance stored in this contract to the owner
         */
        function withdrawTips() public {
            require(owner.send(address(this).balance));
        }
    }
    

### step3 创建一个 buy-coffee.js 脚本来测试你的合约

1.将deploy.js重命名为`buy-coffee.js`

并将代码替换成下面的：（不保存没用啊，要点保存）

    const hre = require("hardhat");
    
    // Returns the Ether balance of a given address.
    async function getBalance(address) {
      const balanceBigInt = await hre.ethers.provider.getBalance(address);
      return hre.ethers.utils.formatEther(balanceBigInt);
    }
    
    // Logs the Ether balances for a list of addresses.
    async function printBalances(addresses) {
      let idx = 0;
      for (const address of addresses) {
        console.log(`Address ${idx} balance: `, await getBalance(address));
        idx ++;
      }
    }
    
    // Logs the memos stored on-chain from coffee purchases.
    async function printMemos(memos) {
      for (const memo of memos) {
        const timestamp = memo.timestamp;
        const tipper = memo.name;
        const tipperAddress = memo.from;
        const message = memo.message;
        console.log(`At ${timestamp}, ${tipper} (${tipperAddress}) said: "${message}"`);
      }
    }
    
    async function main() {
      // Get the example accounts we'll be working with.
      const [owner, tipper, tipper2, tipper3] = await hre.ethers.getSigners();
    
      // We get the contract to deploy.
      const BuyMeACoffee = await hre.ethers.getContractFactory("BuyMeACoffee");
      const buyMeACoffee = await BuyMeACoffee.deploy();
    
      // Deploy the contract.
      await buyMeACoffee.deployed();
      console.log("BuyMeACoffee deployed to:", buyMeACoffee.address);
    
      // Check balances before the coffee purchase.
      const addresses = [owner.address, tipper.address, buyMeACoffee.address];
      console.log("== start ==");
      await printBalances(addresses);
    
      // Buy the owner a few coffees.
      const tip = {value: hre.ethers.utils.parseEther("1")};
      await buyMeACoffee.connect(tipper).buyCoffee("Carolina", "You're the best!", tip);
      await buyMeACoffee.connect(tipper2).buyCoffee("Vitto", "Amazing teacher", tip);
      await buyMeACoffee.connect(tipper3).buyCoffee("Kay", "I love my Proof of Knowledge", tip);
    
      // Check balances after the coffee purchase.
      console.log("== bought coffee ==");
      await printBalances(addresses);
    
      // Withdraw.
      await buyMeACoffee.connect(owner).withdrawTips();
    
      // Check balances after withdrawal.
      console.log("== withdrawTips ==");
      await printBalances(addresses);
    
      // Check out the memos.
      console.log("== memos ==");
      const memos = await buyMeACoffee.getMemos();
      printMemos(memos);
    }
    
    // We recommend this pattern to be able to use async/await everywhere
    // and properly handle errors.
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error);
        process.exit(1);
      });
    

如果你粘贴的是官网的，记得把第五行那个位置换成ethers！！！（如下图所示）

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

2.在控制台输入npx hardhat run scripts/buy-coffee.js，出现下图就对了。

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

### step4 使用 Alchemy 和 MetaMask 将您的 BuyMeACoffe.sol 智能合约部署到以太坊 Goerli 测试网

1.右键点击scipts，点击new file，创建一个名为deploy.js的文件。

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

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

2.在deploy.js中粘贴以下代码。（不保存没用啊，要点保存）

    // scripts/deploy.js
    
    const hre = require("hardhat");
    
    async function main() {
      // We get the contract to deploy.
      const BuyMeACoffee = await hre.ethers.getContractFactory("BuyMeACoffee");
      const buyMeACoffee = await BuyMeACoffee.deploy();
    
      await buyMeACoffee.deployed();
    
      console.log("BuyMeACoffee deployed to:", buyMeACoffee.address);
    }
    
    // We recommend this pattern to be able to use async/await everywhere
    // and properly handle errors.
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error);
        process.exit(1);
      });
    

3.在控制台输入npx hardhat run scripts/deploy.js ，并按回车，出现下面那句BuyMeACoffee deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3就对了。

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

4.打开你的 `hardhat.config.js`文件，您将看到一些示例部署代码。 删除它并将此版本粘贴到其中。记得保存。

    // hardhat.config.js
    
    require("@nomiclabs/hardhat-ethers");
    require("@nomiclabs/hardhat-waffle");
    require("dotenv").config()
    
    // You need to export an object to set up your config
    // Go to https://hardhat.org/config/ to learn more
    
    const GOERLI_URL = process.env.GOERLI_URL;
    const PRIVATE_KEY = process.env.PRIVATE_KEY;
    
    /**
     * @type import('hardhat/config').HardhatUserConfig
     */
    module.exports = {
      solidity: "0.8.4",
      networks: {
        goerli: {
          url: GOERLI_URL,
          accounts: [PRIVATE_KEY]
        }
      }
    };
    

5.在控制台输入npm install dotenv，安装dotenv。如图所示。

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

6.在控制台输入echo test>.env 创建一个.env文件

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

在这里可以看到。

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

7.将以下代码粘贴进.env

    GOERLI_URL=https://eth-goerli.alchemyapi.io/v2/<your api key>
    GOERLI_API_KEY=<your api key>
    PRIVATE_KEY=<your metamask api key>
    

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

**注意：第7步的这三行代码不是最终的，三行全部要换成自己对应的链接，在哪里找，往下看。**

8.替换GOERLI\_URL。

注册一个 [Alchemy](https://alchemy.com/?a=cn-road-to-week-two)帐户。进入dashboard，点击create app。

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

然后如下设置，点击create app。

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

点击view key

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

复制HTTPS的框内内容，切换到vscode，粘贴到如下位置。

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

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

9.替换GOERLI\_API\_KEY。

将API KEY框内内容复制，然后切换到vscode粘贴到如下位置。

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

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

10.替换PRIVATE\_KEY。

点击metamask右上角三个点，然后点击账户详情。

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

点击导出私钥。

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

将下图内容复制。

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

粘贴到这里，然后保存。

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

11.访问 [https://www.goerlifaucet.com](https://www.goerlifaucet.com/) 并使用您的 Alchemy 帐户登录以获得一些免费的测试以太币。

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

12.运行部署脚本npx hardhat run scripts/deploy.js --network goerli ，发现报错，把缺的这个装上去就好了，见13步。

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

13.直接输入npm install --save-dev @nomiclabs/hardhat-waffle 安装第11步的缺的包。安装时有一堆warn不需要管。

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

14.再运行npx hardhat run scripts/deploy.js --network goerli ，出现下面那行BuyMeACoffee deployed to: 某个地址（**这个地址记得复制粘贴下来**）就对了。

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

### step5 实施一个withdraw脚本

1.右键点击script创建withdraw.js文件，将下列代码粘贴进去。

    // scripts/withdraw.js
    
    const hre = require("hardhat");
    const abi = require("../artifacts/contracts/BuyMeACoffee.sol/BuyMeACoffee.json");
    
    async function getBalance(provider, address) {
      const balanceBigInt = await provider.getBalance(address);
      return hre.ethers.utils.formatEther(balanceBigInt);
    }
    
    async function main() {
      // Get the contract that has been deployed to Goerli.
      const contractAddress="0xDBa03676a2fBb6711CB652beF5B7416A53c1421D";
      const contractABI = abi.abi;
    
      // Get the node connection and wallet connection.
      const provider = new hre.ethers.providers.AlchemyProvider("goerli", process.env.GOERLI_API_KEY);
    
      // Ensure that signer is the SAME address as the original contract deployer,
      // or else this script will fail with an error.
      const signer = new hre.ethers.Wallet(process.env.PRIVATE_KEY, provider);
    
      // Instantiate connected contract.
      const buyMeACoffee = new hre.ethers.Contract(contractAddress, contractABI, signer);
    
      // Check starting balances.
      console.log("current balance of owner: ", await getBalance(provider, signer.address), "ETH");
      const contractBalance = await getBalance(provider, buyMeACoffee.address);
      console.log("current balance of contract: ", await getBalance(provider, buyMeACoffee.address), "ETH");
    
      // Withdraw funds if there are funds to withdraw.
      if (contractBalance !== "0.0") {
        console.log("withdrawing funds..")
        const withdrawTxn = await buyMeACoffee.withdrawTips();
        await withdrawTxn.wait();
      } else {
        console.log("no funds to withdraw!");
      }
    
      // Check ending balance.
      console.log("current balance of owner: ", await getBalance(provider, signer.address), "ETH");
    }
    
    // We recommend this pattern to be able to use async/await everywhere
    // and properly handle errors.
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error);
        process.exit(1);
      });
    

如图所示，记得保存。

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

2.在控制台输入npx hardhat run scripts/withdraw.js ,运行后如下图就行。

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

### step6 使用 Replit 和 Ethers.js 构建前端 Buy Me A Coffee 网站 dapp

1.在此处访问官方示例项目，并创建您自己的副本以进行修改： [官方示例项目](https://replit.com/@thatguyintech/BuyMeACoffee-Solidity-DeFi-Tipping-app)

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

2.点击fork repl。

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

3.进入该界面，没用过replit的要注册一下。

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

4.下面那一串合约地址换成你在step4 的第14步得到的BuyMeACoffee deployed to:冒号后面的地址。

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

5.在 pages/index.js 中按ctrl+f将名称字符串更新为您自己的名称。

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

6.点击run，出现如图所示即可。

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

7.点击publish。

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

8.一直点下一步，最后publish即可。

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

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

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

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

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

![这张图链接记得保存](https://storage.googleapis.com/papyrus_images/bac8639bffe87060c776ab807082484c94efc943880fc60293b1b6a31e3014fa.png)

这张图链接记得保存

这张图链接记得保存.

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

9.进入自己创建的网站试着几笔打赏就可以了。

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

### step7 项目提交。

提交[链接](https://alchemyapi.typeform.com/roadtoweektwo)。

注意，最后一步提交内容为

step4 第14步的地址;

step6第8步最后一张图的链接；

你自己的replit主页链接。

### step8 领取NFT。

领取[链接](https://mintkudos.xyz/claim/611)。

---

*Originally published on [ChiefDavid](https://paragraph.com/@chiefdavid/alchemy-road-to-web3-nft)*
