通过Ethers.js 库进行合约交互

  • 木西
  • 发布于 2025-03-05 13:10
  • 阅读 285

前言本文通过Ethersjs库实现和智能合约的交互全流程流程;工具前端项目引入ethersjs库给浏览器安装一个钱包插件例如:MetaMaskopenzeppelin库编写合约合约部分合约//SPDX-License-Identifier:MITpragmasolid

前言

本文通过Ethersjs库实现和智能合约的交互全流程流程;

工具

  1. 前端项目引入ethersjs库
  2. 给浏览器安装一个钱包插件例如:MetaMask
  3. openzeppelin库编写合约

合约部分

合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken1 is ERC20 {
    constructor() ERC20("Mock Token", "MTK") {
        _mint(msg.sender, 1000000 * 10 ** decimals());
    }
}
# 编译
# npx hardhat compile

部署

module.exports = async  ({getNamedAccounts,deployments})=>{
    const getNamedAccount = (await getNamedAccounts()).firstAccount;
    // const getNamedAccount = (await getNamedAccounts()).secondAccount;
    console.log('getNamedAccount',getNamedAccount)
    const TokenName = "ETHToken";
    const TokenSymbol = "ETH";
    const {deploy,log} = deployments;
    const TokenC=await deploy("MyToken1",{
        from:getNamedAccount,
        args: [],//参数
        log: true,
    })
    // await hre.run("verify:verify", {
    //     address: TokenC.address,
    //     constructorArguments: [TokenName, TokenSymbol],
    //     });
    console.log('合约地址1',TokenC.address)
}
module.exports.tags = ["all", "token1"];
# 部署
# npx hardhat deploy

测试

const {ethers,getNamedAccounts,deployments} = require("hardhat");
const { assert,expect } = require("chai");
describe("token", function() {
    let Token1;
    let owner,addr1,addr2;
    beforeEach(async function(){
        await deployments.fixture(["token1"]);
        [owner,addr1,addr2]=await ethers.getSigners();
        // firstAccount = (await getNamedAccounts()).firstAccount;
        const Token1Deployment = await deployments.get("MyToken1");
        Token1 = await ethers.getContractAt("MyToken1",Token1Deployment.address);//已经部署的合约交互
    });
    describe("测试",function(){
        it("测试",async function(){
            console.log('名字:',await Token1.name())
            console.log('符号:',await Token1.symbol())
            console.log('decimals:',await Token1.decimals())
            console.log('totalSupply:',await Token1.totalSupply())
            console.log("owner的额度:",await Token1.balanceOf(owner.address))
            transfer = await Token1.transfer(addr1.address,100)
            console.log('转账余额:',await Token1.balanceOf(addr1.address))
            console.log('授权:',await Token1.approve(addr1.address,500))
            console.log('授权额度:',await Token1.connect(addr1).transferFrom(owner.address,addr2.address,200))
            console.log('addr2的额度:',await Token1.balanceOf(addr2.address))
            console.log('addr1的额度:',await Token1.balanceOf(addr1.address))

        }) 
    })

})
# 测试
# npx hardhat test ./test/xxx.js

前端部分

把部署的合约生成的abi的json文件导入项目中

# 代码
import { ethers ,JsonRpcProvider,BrowserProvider} from "ethers";
import React,{useEffect, useState} from "react";
import tokenABI from '../json/MyToken1.json';//代币合约json文件获取abi
const initFn = async () => {
    const provider = new BrowserProvider(window.ethereum);//浏览器端
    // 读取钱包地址
const accounts = await provider.send("eth_requestAccounts", []);
const account = accounts[0]//获取余额
const balance = await provider.getBalance(account)// 读取chainid
const { chainId } = await provider.getNetwork()
// console.log(await provider.getNetwork())
// console.log(await provider.getBlockNumber())
// console.log(await provider.getTransactionCount('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'))
// console.log(await provider.getFeeData())
// console.log(await provider.getBlock(0))
// console.log(await provider.getCode("0xc778417e063141139fce010982780140aa0cd5ab"))
const signer =await provider.getSigner();//获取signer
    // console.log('signer',signer)
let info={
    chainid:chainId.toString(),
    balance:ethers.formatUnits(balance),
    account:account,
    signer:signer

}
return info

}
let {chainid,balance,account,signer}=await initFn()
let account0='0x5D5Cfb244eD2fEA3138cbA5E6DdC11c8b6D92dD7'//钱包地址0
let acccout1='0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'//钱包地址1
let acccout2=`0x70997970C51812dc3A010C7d01b50e0d17dc79C8`//钱包地址2
let BalanceValue
let ContractAddress='0x8A791620dd6260079BF849Dc5567aDC3F2FdC318';//mtk合约地址
let ContractData=new ethers.Contract(ContractAddress,tokenABI.abi,signer);//合约实例

function  Header() {
    let [chainidv,setChainid]=useState('');//链id
    let [balancev,setBalance]=useState('');//钱包余额
    let [accountv,setAccount]=useState('');//钱包地址
    let [signerv,setSigner]=useState('');//签名
    let [txv,setTxv]=useState('');//实例

    //代币
    let [name,setName]=useState('');//MTK代币名称
    let [symbol,setSymbol]=useState('');//MTK代币符号
    let [totalSupply,setTotalSupply]=useState('');//MTK代币总供应量
    let [balanceOf,setBalanceOf]=useState('');//MTK代币余额
    let [address1,setAddress1]=useState('');//MTK代币地址1
    let [address2,setAddress2]=useState('');//MTK代币地址2
    //转账方法
const transfer=async ()=>{
  const provider = new ethers.BrowserProvider(window.ethereum);//浏览器端
  // const provider = new ethers.JsonRpcProvider();//浏览器端
  const value = ethers.parseEther('100'); 
  const signer =await provider.getSigner()
  const tx = await signer.sendTransaction({
        to: account0,
        value: value//转换100eth
  })
  console.log(tx)

  if(tx){
    await tx.wait();
    console.log('转账成功')
   let Balance=await provider.getBalance(account0)
   BalanceValue=ethers.formatUnits(Balance)
   localStorage.setItem('BalanceValue',BalanceValue)
   setTxv(BalanceValue)

  }else{
    console.log('失败')
  }

}
//读取MTK合约信息
const getContractInfo=async ()=>{
  setName(await ContractData.name())
  setSymbol(await ContractData.symbol())
  let totalSupply=ethers.formatUnits(await ContractData.totalSupply())
  setTotalSupply(totalSupply)
}
//转账MYK代币合约
const mtktransfer=async ()=>{
  console.log('转账',await ContractData.transfer(acccout2,ethers.parseEther('100')))
  let addr1=ethers.formatUnits(await ContractData.balanceOf(acccout1))
  console.log('address',addr1)
  let addr2=ethers.formatUnits(await ContractData.balanceOf(acccout2))
  setAddress1(addr1) 
  setAddress2(addr2)
  console.log('address',addr2)
}
      useEffect(()=>{
        setChainid(chainid)
        setBalance(balance)
        setAccount(account)
        setSigner(signer)

      },[accountv])
      useEffect(()=>{
        setTxv(BalanceValue)
        // console.log(BalanceValue)
        // console.log(txv)
      },[txv])
    return (<>
            {
             window.ethereum===undefined?<div style={{color:'red'}}>
             请按照要求安装metamask
             </div> :<div style={{padding:'10px'}}>
                <h4 style={{fontSize:'20px',lineHeight:'40px',fontWeight:'bold'}}>钱包信息</h4>
                <p><strong>chainid</strong>: {chainidv}</p>
                <p><strong>钱包余额:</strong> {balancev} ETH</p>
                <p><strong>钱包地址:</strong> {accountv}</p>
                <p><strong>signeraddress:</strong> {signerv.address}</p>
                <p><strong>账号:</strong>{account0}<br/><strong>转账余额:</strong>{txv || localStorage.getItem('BalanceValue')}</p>
                <button onClick={transfer} style={{background:'#065ae6cf',color:'#fff',padding:'10px 20px',borderRadius:'5px',margin:'10px 0'}}>转账按钮</button>

                <div>
                  <h1 style={{fontWeight:'bold',fontSize:'20px',margin:"10px 0"}}>合约信息面板</h1>
                  <p><strong>代币名:</strong>{name}</p>
                  <p><strong>代币符号:</strong>{ symbol}</p>
                  <p><strong>代币总供应量:</strong>{ totalSupply} MTK</p>
                  <button onClick={getContractInfo} style={{background:'#065ae6cf',color:'#fff',padding:'10px 20px',borderRadius:'5px',margin:'10px 0'}}>读取信息</button>
                  <p><strong>address1余额:</strong>{  address1} MTK</p>
                  <p><strong>address2余额:</strong>{  address2} MTK</p>
                  <button onClick={mtktransfer} style={{background:'#065ae6cf',color:'#fff',padding:'10px 20px',borderRadius:'5px',margin:'10px 0'}}>转账</button>
                </div>
              </div>

            }
            </>)
}
export default Header;

预览效果

屏幕截图 2025-03-03 214102.png

钱包设置

钱包插件添加自定义网络<br/>

  1. 启动本地节点获取账户节点

<!---->

# 会获取到20个账户,每个账户中有10000 ETH
npx hardhat node//获取节点账号

如图所示

屏幕截图 2025-03-03 174703.png 2. 添加自定网络 <br> 步骤如下

屏幕截图 2025-03-03 175539.png

屏幕截图 2025-03-03 175234.png

屏幕截图 2025-03-03 180118.png

自定义网络说明:网络名为:LY URL:127.0.0.1:8545 链ID: 31337 货币符号: ETH<br>

把本地账号导入到自定义网络中:

屏幕截图 2025-03-03 180844.png

屏幕截图 2025-03-03 180944.png

把本地节点的私有粘贴到输入框中导入成功后可以获取一个含有10000ETH的账号 屏幕截图 2025-03-03 181016.png

在钱包插件中导入合约

  • 本地部署合约获取合约地址

<!---->

npx hardhat deploy

屏幕截图 2025-03-03 192912.png

屏幕截图 2025-03-03 193017.png

屏幕截图 2025-03-03 193025.png

屏幕截图 2025-03-03 193109.png

合约交互

说明:主要通过ethers中的Contract实现合约的交互

import { ethers ,JsonRpcProvider,BrowserProvider} from "ethers";
import tokenABI from '../json/MyToken1.json';//代币合约json文件获取abi
const provider = new BrowserProvider(window.ethereum);//浏览器端
const signer =await provider.getSigner();//获取signer 合约可读写
let ContractAddress='0x8A791620dd6260079BF849Dc5567aDC3F2FdC318';//mtk合约地址
let ContractData=new ethers.Contract(ContractAddress,tokenABI.abi,signer);//合约实例
//通过合约实例实现合约交互
//例如

let name await ContractData.name()//获取代币的name

点击转账按钮和合约交互

点击2025-03-03 214102.png

调起钱包:账号2向账号3转了100MTK

屏幕截图 2025-03-03 214931.png

点击确定按钮 在钱包插件或界面查看两个账户的余额

屏幕截图 2025-03-03 214956.png

转账余额2025-03-03 214102.png

总结

以上就是简单的通过ethers和智能合约的交互全部流程,本地测试需要启动本地节点 npx hardhat node,编译部署合约,获取合约地址和abijson文件,把abi文件导入前端项目用来实现合约的交互;

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
木西
木西
江湖只有他的大名,没有他的介绍。