首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >以太坊合约交互

以太坊合约交互

作者头像
Maic
发布2025-07-30 14:06:34
发布2025-07-30 14:06:34
9300
代码可运行
举报
文章被收录于专栏:Web技术学苑Web技术学苑
运行总次数:0
代码可运行

背景

主要学习了解如何写一个合约,如何在前端进行合约交互,以一段最简单的合约代码学习合约交互的流程

我们知道以太坊合约代码是用solidity语言来写的,我们使用hardhat初始化一个编写合约开发环境文档参考[1],以下是一篇学习笔记,希望看完有所帮助

初始化项目

代码语言:javascript
代码运行次数:0
运行
复制
npx hardhat init

我们在contracts文件夹下新建一个Count.sol合约代码

代码语言:javascript
代码运行次数:0
运行
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
// 定义了一个Hello合约
contract Hello {
   // 申明公有变量
   string public name = "Hello World";
   uint public count = 0;
   function increment() public {
       count++;
   }
   function desc() public {
       count--;
   }
   function get() public view returns (uint) {
       return count;
   }
}

当我们写好合约后,我们需要编译合约,执行npx hardhat compile,当我们执行命令后,会生成一个artifacts存储合约编译后的文件,这个abi数据映射的就是合约代码,在前端调用需要这个abi数据

代码语言:javascript
代码运行次数:0
运行
复制
{
  "_format": "hh-sol-artifact-1",
"contractName": "Hello",
"sourceName": "contracts/Count.sol",
"abi": [
    {
      "inputs": [],
      "name": "count",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "desc",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "get",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "increment",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    }
  ],
  ...
}

当我们编译好本地合约,我们需要部署合约,因此我们开启本地

代码语言:javascript
代码运行次数:0
运行
复制
npx hardhat node
代码语言:javascript
代码运行次数:0
运行
复制
Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/

Accounts
========

WARNING: These accounts, and their private keys, are publicly known.
Any funds sent to them on Mainnet or any other live network WILL BE LOST.

Account #0: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000 ETH)
Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

我们在script目录下新建一个deploy.js

代码语言:javascript
代码运行次数:0
运行
复制
// scripts/deploy.js
const hre = require("hardhat");

asyncfunction main() {
const Hello = await hre.ethers.getContractFactory("Hello");
const hello = await Hello.deploy();

console.log("Hello deployed to:", hello.target);
}

main().catch((error) => {
console.error(error);
  process.exitCode = 1;
});

部署合约,执行hardhat run scripts/deploy.js --network localhost,会生成一个部署的合约地址contractAddress

代码语言:javascript
代码运行次数:0
运行
复制
work localhost
Hello deployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512

我们已经编译并部署了合约,如何在前端调用呢

首先我们需要把本地rpc添加到metaMask中,就是我们之前运行的本地rpc

  • rpc http://127.0.0.1:8545/
  • 链ID 31337【hardhat默认链id】
  • 货币符号 ETH

然后我们将npx hardhat node本地运行生成的测试账号,倒入一个私钥到钱包里就行

基础的准备工作已经完成

在前端里,我们需要读取合约,以及调用合约方法

代码语言:javascript
代码运行次数:0
运行
复制
  <div className="app">
        <h1>Hello Contract</h1>
        <p onClick={handleWalletConnect}>Connect Wallet</p>
        <button onClick={handleDiscontent}>discontent wallet</button>
        <p>address:{address}</p>
        <p>Count: <span id="count">{count}</span></p>
        <button onClick={getCount}>Get</button>
        <button onClick={increment}>Increment</button>
        <button onClick={desc}>Decrement</button>
   </div>
  • 连接钱包
代码语言:javascript
代码运行次数:0
运行
复制
  import {ethers, BrowserProvider, Contract} from "ethers";
  ...
  const handleWalletConnect = async () => {
    await window.ethereum.request({ method: "eth_requestAccounts" });
    const provider = new BrowserProvider(window.ethereum); 
    const signer = await provider.getSigner();
    const address = await signer.getAddress();
    console.log(address, "===address");
    setAddress(address);
  }

获取Contract

  • 获取provider
  • 获取signer
  • 主要调用合约方法是new Contract(contractAddress, abi, signer)
代码语言:javascript
代码运行次数:0
运行
复制
import {ethers, BrowserProvider, Contract} from "ethers";
const provider = new BrowserProvider(window.ethereum); 
const signer = await provider.getSigner();
const contract = 以下是部分调用合约代码 Contract(contractAddress, abi, signer);

以下是部分调用合约带哪

代码语言:javascript
代码运行次数:0
运行
复制
import {ethers, BrowserProvider, Contract} from"ethers";

...
const [count, setCount] = useState(0);
const contractRef = useRef(null);
const [address, setAddress] = useState("")

const isWalletAuthorized = async () => {
    const accounts = awaitwindow.ethereum.request({ method: "eth_accounts" });
    return accounts.length > 0;
  };
const checkIfWalletConnected = async () => {
    try {
      if (isWalletAuthorized()) {
        const provider = new BrowserProvider(window.ethereum);
        const signer = await provider.getSigner();
        const address = await signer.getAddress();
        setAddress(address);
        const contract = new Contract(contractAddress, abi, signer);
        contractRef.current = contract;
        await getCount();
      }
    } catch (err) {
      console.warn("检查钱包失败", err);
    }
  };

const getCount = async () => {
    const count = await contractRef.current.get();
    console.log(count);
    setCount(count);
  }

  useEffect(() => {
    checkIfWalletConnected();
  }, [])

当我们遇到这种错误时,因为其他插件影响,关闭okx插件钱包,只留metaMask。这种错误是由于okx插件修改了window.ethereum冲突造成的。

代码语言:javascript
代码运行次数:0
运行
复制
VM66 inpage.js:1 w[0].read is not a function RPC Stack: -> wallet_requestUnlockUI -> wallet_requestPermissions - in wallet_requestUnlockUI [ServerError -32000]

1.  {code: -32000, message: 'w[0].read is not a function\nRPC Stack:\n-> wallet_r…- in wallet_requestUnlockUI [ServerError -32000]\n'}

当我们查询合约的count,调用就是合约的get方法

代码语言:javascript
代码运行次数:0
运行
复制
  const getCount = async () => {
    const count = await contractRef.current.get();
    console.log(count);
    setCount(count);
  }

当我们调用increment

代码语言:javascript
代码运行次数:0
运行
复制
...
  const increment = async () => {
    const tx = await contractRef.current.increment();
    await tx.wait();
    await getCount();
  }

时就会打开metaMask钱包发送交易请求,我们看到会产生交易请求increment时就会打开metaMask钱包发送交易请求,我们会看到会产生交易请求

至此与链上合约交户就完成了

总结

  • 参考hardhat官方文档写一个简单的测试合约代码
  • 如何编译部署本地合约
  • 在前端如何测试合约并调用合约代码与钱包进行交互
  • code example[2]

参考资料

[1]

文档参考: https://hardhat.org/hardhat-runner/docs/getting-started#overview

[2]

code example: https://github.com/maicFir/SolidityLesson/tree/master/17-test

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Web技术学苑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 初始化项目
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档