Skip to content

1. 构建本地测试网络

bash
// 在命令行中执行
anvil

获取到本地RPC URL地址127.0.0.1:8545 如图下结果所示,则表示本地测试网络已经启动:

anvil

2.forge 构建项目写个 HelloWorld 合约

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

contract HelloWorld {
    string public showMsg='hello world';

    function showSomeMsg() public view returns(string memory){
        return showMsg;
    }

    function getMsg(string calldata newMsg) public pure returns(string calldata){
        return newMsg;
    }
}

写了两个函数,viewpure都是不用花费 gas。

3.编译合约,获取到对应的 ABI 文件

bash
forge build

在项目根目录下找到 out,把 HelloWorld.json 文件拷贝到前端项目目录下(也可放线上等待前端来请求)。

4.部署合约到本地测试网络

先取本地没测试帐号的地址,我取了第一个0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,如果是 windows 系统,配置一下环境变量,ETH_FROM=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,再好下配置 foundry.toml 文件,配置如下:

toml
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
rpc_url = "anvil"
private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"

[rpc_endpoints]
anvil = "http://127.0.0.1:8545"

// 上面的私钥也是取的第一个帐户对应的私钥

所有配置完成后,执行以下命令,部署合约到本地测试网络:

bash
 forge create --unlocked src\HelloWorld.sol:HelloWorld

执行成功后,会返回合约地址,如下所示:

bash
Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
Transaction hash: 0x2679c0995453ab9b31eb49477704a5ee7dab2c183db0ce8d476e04375d4704a9

上面的值在前端中要用到。

5.构建一个 React 前端项目

在前端与合约交互,需要用到 ethers.js 库,按如下配置:

ts
import { ethers } from 'ethers'
// 合约 ABI
import HelloWorldContractABI from '../../public/ABI/HelloWorld.json' assert { type: 'json' }
// 合约部署地址
const contractAddress = '0x5FbDB2315678afecb367f032d93F642f64180aa3'
// 本地测试网络 RPC 地址
const rpcUrl = 'http://127.0.0.1:8545'
async function getContract() {
  const provider = new ethers.JsonRpcProvider(rpcUrl)
  const contract = new ethers.Contract(
    contractAddress,
    HelloWorldContractABI.abi,
    provider,
  )
  return contract
}
const contract = await getContract()
export { contract }

6.前端调用合约的两个函数

前端代码如下:

import { useState } from 'react'
import './App.css'
import { contract } from './utils/contract'

function App() {
  const [pure, setPure] = useState('')
  const [view, setView] = useState('')
  const pureFunc = async () => {
    const res = await contract.getMsg('我是React')
    setPure(res)
  }
  const viewFunc = async () => {
    const res = await contract.showSomeMsg()
    setView(res)
  }

  return (
    <>
      <div className="card">
        <button onClick={pureFunc}>调用合约pure函数</button>
        <p>合约调用返回值:{pure}</p>
      </div>
      <div className="card">
        <button onClick={viewFunc}>调用合约view函数</button>
        <p>合约调用返回值:{view}</p>
      </div>
    </>
  )
}

调用成功后,页面显示如下:

contract.png