Alchemy第二周教程

电脑需要安装 ubuntu 和 visual studio code 安装后管理员 ubuntu 运行

mkdir BuyMeACoffee-contracts 
cd BuyMeACoffee-contracts

npm init -y

npx hardhat

运行成功后选择第一个一直回车创建新项目

post image

完成后界面

post image

输入

Code .

会跳转打开code软件  (code内容修改后都需要手动点击保存)

post image

右键重命名为 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));

    }

}

 

右键重命名为buy-coffee.js

post image

内容修改为:

const hre = require("hardhat");

 

// Returns the Ether balance of a given address.

async function getBalance(address) {

  const balanceBigInt = await hre.waffle.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);

  });

终端运行npx hardhat run scripts/buy-coffee.js 查看是否有报错如果没有报错,会出来一个合约如下图。

post image

在code内右键新建文件deploy.js

post image

内容为:

// 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);

});

运行npx hardhat run scripts/deploy.js  查看是否有报错,如果没报错会出现一个合约代码,如下图:

post image

点击hardhat.config.js 将内容修改为:

post image
// 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]

}

}

};

运行npm install dotenv

post image

运行touch .env

post image

填充 env内容

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

https://www.alchemy.com/  在这里注册,新建

post image

GOERLI_UL为 https链接 GOERLI_API_KEY 为 api-key

PRIVATE_KEY为小狐狸私钥(创建新账号)

post image

如下图

post image

运行npx hardhat run scripts/deploy.js --network goerli 查看是否报错,如果没报错,会出现一个合约地址,如下图

post image

如果报错,如下图 选择的2行代码修改为一行:

require("@nomicfoundation/hardhat-toolbox");

post image

修改后再次运行npx hardhat run scripts/deploy.js --network goerli 创建合约,如果继续报错,看一下报错原因是什么。

https://goerli.etherscan.io/  运行成之后就可以去里面查询合约 并且复制合约链接备用(填表要用)

新建文件再code中内容保存为:

post image
// 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://replit.com/@thatguyintech/BuyMeACoffee-Solidity-DeFi-Tipping-app

点击

post image

代码修改为自己创建的合约地址

post image

ctrl + F  搜索Albert  可以修改自己的昵称 随便改

post image

点击发布  内容自己填

post image

复制填表用

post image

复制填表用

post image

在新窗口打开复制的这个链接

post image

运行后使用小狐狸交互一下  结束

post image
post image

填表

https://alchemyapi.typeform.com/roadtoweektwo

最后一项要填3个添加, 第一个是合约链接(是链接,不是地址)  第二、三是结尾上面让复制的2个链接。