关注

8. web3.js调用合约方法

Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - web3.js调用合约方法

一. 系列视频
二. 系列文章

1. Remix编写、编译、部署、测试Solidity ERC20合约 - 基础篇
2. Remix编写、编译、部署、测试Solidity ERC20合约 - 进阶篇
3. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 基础篇
4. JSON-RPC调用区块链方法
5. JSON-RPC调用合约方法
6. JSON-RPC给合约账户同时转以太币和代币
7. web3.js调用区块链方法
8. web3.js调用合约方法
9. web3.js给合约账户同时转以太币和代币
10. Go-Ethereum调用区块链方法
11. Go-Ethereum调用合约方法
12. sendTransaction和sendRawTransaction区别
13. Metamask导入代币,转账ETH,转账代币 - 界面操作
14. Metamask连接hardhat本地节点
15. DAPP react界面-web3.js库-Metemask调用和显示-调用合约方法
16. web3js结合sepolia测试网
17. 总结

对比系列中的此篇文章
7. JSON-RPC调用合约方法
5. web3.js调用区块链方法

1. 以太坊通信协议

详见 7. JSON-RPC调用合约方法

2. 编写调试代码

以太坊JSON-RPC API

合约代码
基于ERC20的智能合约

// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.4.0
pragma solidity ^0.8.27;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
    constructor() ERC20("MyToken", "MTK") payable  {
        _mint(msg.sender, 100 * 10 ** decimals());
    }
    fallback() external payable { }
    receive() external payable { }
}

读操作用eth_call,写操作用eth_sendTransaction。
读操作,将method赋值给eth_call。合约地址放入to,方法名和参数放入data,赋值给params,组装jsonrpc。
读操作不消耗gas,从本地节点直接返回,不组装交易结构,不进行挖矿。所以不需要交易结构中的from、value、gaslimit、gasprice。
写操作消耗gas,广播到区块链上的节点,组装交易结构,进行挖矿。所以需要交易结构中的from、gaslimit、gasprice,默认不需要value。

web3.js在构造合约对象时,已经持有合约地址
const contract = new web3.eth.Contract(abi, contractAddress);

查询代币名称的JSON-RPC结构:

web3.js的调用方式:
await contract.methods.name().call()

底层构建的JSON-RPC结构:
{
	jsonrpc: '2.0',
	method: 'eth_call',
	params: [{
        to: contractAddress,
        data: keccak256(Buffer.from('name()')).slice(0, 10)
    }, 'latest'],
	id: 1
}

查询余额的JSON-RPC结构:

web3.js的调用方式:
await contract.methods.balanceOf(accountAddr).call()

底层构建的JSON-RPC结构:
{
	jsonrpc: '2.0',
	method: 'eth_call',
	params: [{
        to: contractAddress,
        data: keccak256(Buffer.from('balanceOf(address)')).slice(0, 10) + accountAddr.toLowerCase().replace('0x', '').padStart(64, '0')
    }, 'latest'],
	id: 1
}

转账的JSON-RPC结构:

web3.js的调用方式:
await contract.methods.transfer(recAccountAddr, value).send({from: sendAccountAddr, gas: 3000000});

底层构建的JSON-RPC结构:
{
	jsonrpc: '2.0',
	method: 'eth_sendTransaction',
	params: [{
        from: sendAccountAddr,
        to: contractAddr,
        data: keccak256(Buffer.from('transfer(address,uint256)')).slice(0, 10) + recAccountAddr.toLowerCase().replace('0x', '').padStart(64, '0') + BigInt(value).toString(16).padStart(64, '0'),
        gas: '0x300000'
    }],
	id: 1
}
总结一下,web3.js的设计逻辑是:
1. method字段由.call().send()决定。读操作用.call(),赋值'eth_call',写操作用.send(),赋值'eth_sendTransaction'2. params字段中的第一个元素是交易结构对象,to属性是合约地址,data属性是合约中方法和参数。通过const contract = new web3.eth.Contract(abi, contractAddress)来组装。

3. 编写调试代码

const { ethers } = require("hardhat");
const { default: Web3 } = require('web3');
const fs = require('fs');
const path = require('path');

const fromAddress = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266';
const toAddress = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8';

// 部署合约
async function deploy() {
  // 获取合约工厂(这里期望存在名为 Token 的合约,位于 contracts/ 下)
  // 注意:合约名需与 solidity 文件中合约名一致。
  const myContract = await ethers.getContractFactory("MyToken");
  const token = await myContract.deploy();
// 等待链上确认
  await token.waitForDeployment();
  const address = await token.getAddress();
  console.log("实际合约地址:", address);

  return address;
}

// web3js调用合约方法
async function web3js(contractAddress) {

    // 读取编译生成的合约 ABI 文件
    const artifact = JSON.parse(fs.readFileSync(path.join(__dirname, '../../artifacts/contracts/Lock.sol/MyToken.json'), 'utf8'));
    const abi = artifact.abi;

    // 连接本地区块链节点
    const web3 = new Web3("http://localhost:8545");
    // web3.js 合约实例
    const contract = new web3.eth.Contract(abi, contractAddress);

    // ERC20 name, symbol, totalSupply, decimals, balanceOf方法
    var name = await contract.methods.name().call();
    console.log("Token Name:", name);

    var symbol = await contract.methods.symbol().call();
    console.log("Token Symbol:", symbol);

    console.log("发送前MTK:", await contract.methods.balanceOf(fromAddress).call() / BigInt(1e18));
    console.log("接收前MTK:", await contract.methods.balanceOf(toAddress).call() / BigInt(1e18));

    // ERC20 transfer方法
    var receipt = await contract.methods.transfer(toAddress, web3.utils.toWei(10, 'ether')).send({from: fromAddress, gas: 3000000});
    
    console.log("发送后MTK:", await contract.methods.balanceOf(fromAddress).call() / BigInt(1e18));
    console.log("接收后MTK:", await contract.methods.balanceOf(toAddress).call() / BigInt(1e18));
}

async function main() {
    var address = await deploy();
    
    console.log("web3js 调用合约方法:");
    await web3js(address);
}

main().then();

4. 安装依赖

npm install web3

5. 启动Hardhat本地节点

npx hardhat node

在这里插入图片描述

6. 调试

npx hardhat run ignition\modules\Mytoken.js --network localhost
在这里插入图片描述

hardhat node输出
在这里插入图片描述

一. 系列视频
二. 系列文章

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/tianma2012/article/details/156340960

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--