1.react+ethers+hardhat DApp初试

624 阅读2分钟

今天较为完整的完成了一个简单的dapp的demo

通过hardhat框架写合约并编译部署合约 通过ethers与合约交互 通过在react项目中引入ethers库来使用

总的三步:合约编译部署,连接metamsk,连接react

  1. 创建一个react项目
npx create-react-app react-dapp
  1. 进入目录安装hardhat和ethers
npm install ethers hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers
  1. hardhat初始化环境
npx hardhat
  1. 打开hardhat.config.js文件,配置如下
 solidity: "0.8.18",
  paths: {
  //编译后生成json的路径
    artifacts: './src/artifacts',
  },
  networks: {
  //本地网络用这个
     hardhat: {
       chainId: 1337
     },
  //对应的测试网用这个,我用的alchemy
    sepolia:{
    //测试网url
      url:"",
    //账户私钥  
      accounts:[""]
    }
  }
  1. hardhat自带的一个模板合约lock.sol

合约定义了两个变量,一个事件和一个函数

通过构造器在合约部署时给合约存定量的数值和锁定时间 当到达锁定时间且是存款人时可以提现

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

// Uncomment this line to use console.log
// import "hardhat/console.sol";

contract Lock {

    uint public unlockTime;
    address payable public owner;

    event Withdrawal(uint amount, uint when);

    //构造器,输入锁定时间
    constructor(uint _unlockTime) payable {
        // 当前时间戳小于锁定时间
        require(block.timestamp < _unlockTime,"Unlock time should be in the future");
        unlockTime = _unlockTime;
        owner = payable(msg.sender);
    }

    // 提现函数
    function withdraw() public {
        // Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal
        // console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp);
        require(block.timestamp >= unlockTime, "You can't withdraw yet");
        require(msg.sender == owner, "You aren't the owner");
        
        // 记录提现金额和时间
        emit Withdrawal(address(this).balance, block.timestamp);

        // 给owner转当前余额
        owner.transfer(address(this).balance);
    }
}

6.编译合约获得abi json文件

npx hardhat compile

这个时候可能或出现找不到 hardhat-toolbox的问题 直接npm下载 还有vscode打开文件会跳出什么wsl的下载,要下载,不下载也会一直报错

  1. 使用该合约时,在js中导入
import Lock from './artifacts/contracts/Lock.sol/Lock.json'

然后通过Lock.abi使用对应的合约

  1. 部署到本地网络,首先启动本地测试节点 开一个终端输入命令
npx hardhat node

会得到10个节点账户地址和私钥

  1. 部署合约
/*
 * @Author: diana
 * @Date: 2023-04-12 09:58:53
 * @LastEditTime: 2023-04-12 21:09:40
 */
import { ethers } from "hardhat";

async function main() {
  const currentTimestampInSeconds = Math.round(Date.now() / 1000);

  // 锁定时间,当前时间加60秒
  const unlockTime = currentTimestampInSeconds + 60;
  // 存储金额
  const lockedAmount = ethers.utils.parseEther("0.004");

  // 通过合约实例部署合约并初始化给合约转账
  const Lock = await ethers.getContractFactory("Lock");
  const lock = await Lock.deploy(unlockTime, { value: lockedAmount });

  await lock.deployed();

  console.log(
    `Lock with ${ethers.utils.formatEther(lockedAmount)}ETH and unlock timestamp ${unlockTime} deployed to ${lock.address}`
  );
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

新开一个终端部署在本地网络

npx hardhat run scripts/deploy.ts --network localhost
  1. metamask连接测试网络localhost:8575并导入测试节点

  2. 连接react app.js

/*
 * @Author: diana
 * @Date: 2023-04-12 09:55:25
 * @LastEditTime: 2023-04-12 21:12:10
 */
// import logo from './logo.svg';
import './App.css';
// import {useState} from 'react';
import {ethers} from 'ethers';
// 引入合约编译后json
import Lock from './artifacts/contracts/Lock.sol/Lock.json'

// 合约地址
const contracAddress = '0xa0f09984150388b2f4D4E44B42774D183087D545'

function App() {
  // 获取用户钱包地址
  async function requestAccount(){
    // MetaMask会向网页注入一个全局的API变量window.ethereum
    //该API允许 网站请求用户登录,可以从用户接入的区块链读取数据,并切能够提示用户签名 要提交的交易。
    const account = await window.ethereum.request({method:'eth_requestAccounts'})
    console.log("调用成功",account)
  }

  async function withdraw(){
  
    if(typeof window.ethereum !== 'undefined'){
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const singer = provider.getSigner();
      // 可写合约
      const contract = new ethers.Contract(contracAddress,Lock.abi,singer)
      
      try{
        const data =  await contract.withdraw();
        console.log(data)
      }catch(err){
        console.log(`err: ${err}`)
      }

      contract.on("Withdrawal",function(amount,when){
        console.log(`${when}时提现${amount}`)
      })
    }
  }

  return (
    <div className="App">
      <button type="button" onClick={requestAccount}>获取用户钱包地址</button>

      <button type="button" onClick={withdraw}>提现</button>
    </div>
  );
}
export default App;

13.效果: 点击按钮 image.png