今天较为完整的完成了一个简单的dapp的demo
通过hardhat框架写合约并编译部署合约 通过ethers与合约交互 通过在react项目中引入ethers库来使用
总的三步:合约编译部署,连接metamsk,连接react
- 创建一个react项目
npx create-react-app react-dapp
- 进入目录安装hardhat和ethers
npm install ethers hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers
- hardhat初始化环境
npx hardhat
- 打开hardhat.config.js文件,配置如下
solidity: "0.8.18",
paths: {
//编译后生成json的路径
artifacts: './src/artifacts',
},
networks: {
//本地网络用这个
hardhat: {
chainId: 1337
},
//对应的测试网用这个,我用的alchemy
sepolia:{
//测试网url
url:"",
//账户私钥
accounts:[""]
}
}
- 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的下载,要下载,不下载也会一直报错
- 使用该合约时,在js中导入
import Lock from './artifacts/contracts/Lock.sol/Lock.json'
然后通过Lock.abi使用对应的合约
- 部署到本地网络,首先启动本地测试节点 开一个终端输入命令
npx hardhat node
会得到10个节点账户地址和私钥
- 部署合约
/*
* @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
-
metamask连接测试网络localhost:8575并导入测试节点
-
连接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.效果:
点击按钮