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

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

  • [1. 安装依赖](#1. 安装依赖)
  • [2. 启动Hardhat本地节点](#2. 启动Hardhat本地节点)
  • [3. 编写调试代码](#3. 编写调试代码)
  • [4. 合约部署到本地节点](#4. 合约部署到本地节点)
  • 5.思考

系列文章
1. Remix编写、编译、部署、测试Solidity ERC20合约 - 基础篇
2. Remix编写、编译、部署、测试Solidity ERC20合约 - 进阶篇
3. Metamask导入代币,转账ETH,转账代币
4. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 基础篇
5. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - web3.js调用合约方法
6. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - web3.js调用区块链方法
7. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - JSON-RPC调用合约方法
8. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - JSON-RPC调用区块链方法
9. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 总结

对比系列中的此篇文章
5. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - web3.js调用合约方法

1. 安装依赖

npm install web3

2. 启动Hardhat本地节点

npx hardhat node

3. 编写调试代码

clike 复制代码
const { ethers } = require("hardhat");
const { default: Web3 } = require('web3');
const { keccak256 } = require("ethers");

// 部署合约
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;
}

// JSON-RPC调用合约方法-读操作
async function jsonrpc_read_contract(contractAddress, funcName, accountAddr='') {
    const name = await http('eth_call', [{
        to: contractAddress,
        // 拼接函数选择器和参数,函数取前四字节作为选择器,参数按ABI编码规则补齐64字节
        data: keccak256(Buffer.from(funcName)).slice(0, 10) + (accountAddr!=''? accountAddr.toLowerCase().replace('0x', '').padStart(64, '0') : '')
    }, 'latest']);
}

// JSON-RPC调用合约方法-写操作
async function jsonrpc_write_contract(sendAccountAddr, contractAddr, funcName, recAccountAddr, value) {
    const name = await http('eth_sendTransaction', [{
        from: sendAccountAddr,
        to: contractAddr,
        data: keccak256(Buffer.from(funcName)).slice(0, 10) + recAccountAddr.toLowerCase().replace('0x', '').padStart(64, '0') + BigInt(value).toString(16).padStart(64, '0'),
        gas: '0x300000'
    }]);
}

async function http(method, params) {
    const response = await fetch('http://localhost:8545', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
            jsonrpc: '2.0',
            method,
            params,
            id: 1
        })
    });
    
    const data = await response.json();
    // console.log('JSON-RPC Raw Response:', data);
    if(data.result.length > 66)
        console.log(method + ':', new Web3().eth.abi.decodeParameter('string', data.result));
    else if(BigInt(data.result))
        console.log(method + ':', BigInt(data.result));
}

async function jsonRpc(contractAddress) {
    // 无参方法
    await jsonrpc_read_contract(contractAddress, 'name()');
    await jsonrpc_read_contract(contractAddress, 'symbol()');
    await jsonrpc_read_contract(contractAddress, 'totalSupply()');
    await jsonrpc_read_contract(contractAddress, 'decimals()');
    // 有参方法
    await jsonrpc_read_contract(contractAddress, 'balanceOf(address)', '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266');
    // sendAccountAddr调用contractAddr合约中的transfer方法, 给recAccountAddr账户转value个MTK代币
    await jsonrpc_write_contract('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', contractAddress, 'transfer(address,uint256)', '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', 1000);
}

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

main().then();

读操作用eth_call,写操作用eth_sendTransaction。

JSON-RPC结构:

clike 复制代码
{
	jsonrpc: '2.0',
	method,
	params,
	id: 1
}

读操作,将method赋值给eth_call。合约地址放入to,方法名和参数放入data,赋值给params,组装jsonrpc。

读操作不消耗gas,从本地节点直接返回,不组装交易结构,不进行挖矿。所以不需要交易结构中的from、value、gaslimit、gasprice。

写操作消耗gas,广播到区块链上的节点,组装交易结构,进行挖矿。所以需要交易结构中的from、gaslimit、gasprice,默认不需要value。

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

clike 复制代码
{
	jsonrpc: '2.0',
	method: 'eth_call',
	params: {
        to: contractAddress,
        data: keccak256(Buffer.from('name()')).slice(0, 10)
    }, 'latest'],
	id: 1
}

查询余额的JSON-RPC结构:

clike 复制代码
{
	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结构:

clike 复制代码
{
	jsonrpc: '2.0',
	method: 'eth_call',
	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
}
clike 复制代码
// sendAccountAddr调用contractAddr合约中的transfer方法, 给recAccountAddr账户转value个MTK代币
    await jsonrpc_write_contract('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', contractAddress, 'transfer(address,uint256)', '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', 1000);
// JSON-RPC调用合约方法-写操作
async function jsonrpc_write_contract(sendAccountAddr, contractAddr, funcName, recAccountAddr, value) {
    const name = await http('eth_sendTransaction', [{
        from: sendAccountAddr,
        to: contractAddr,
        data: keccak256(Buffer.from(funcName)).slice(0, 10) + recAccountAddr.toLowerCase().replace('0x', '').padStart(64, '0') + BigInt(value).toString(16).padStart(64, '0'),
        gas: '0x300000'
    }]);
}

sendAccountAddr账户调用contractAddr合约中的transfer方法, 给recAccountAddr账户转value个MTK代币

funcName(recAccountAddr, value)是合约方法和参数,调用transfer(address,uint256),给'0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'转账1000MTK。

from: sendAccountAddr,

to: contractAddr,是交易参数,消耗ETH。

4. 合约部署到本地节点

npx hardhat run ignition\modules\Mytoken.js --network localhost

hardhat node输出

5.思考

读操作没有输入from,hardhat node输出了from。是因为hardhat node输出日志时,用第一个账户地址作为from。后续文章会进一步探索。

系列文章
1. Remix编写、编译、部署、测试Solidity ERC20合约 - 基础篇
2. Remix编写、编译、部署、测试Solidity ERC20合约 - 进阶篇
3. Metamask导入代币,转账ETH,转账代币
4. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 基础篇
5. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - web3.js调用合约方法
6. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - web3.js调用区块链方法
7. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - JSON-RPC调用合约方法
8. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - JSON-RPC调用区块链方法
9. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 总结

相关推荐
Gofarlic_OMS2 小时前
从Adobe到SolidWorks:研发设计软件资产管理的现状分析
数据库·安全·adobe·oracle·金融·区块链
Rockbean2 小时前
3分钟Solidity: 7.6 Yul语言简介
web3·智能合约·solidity
Gofarlic_OMS3 小时前
通过MathWorks API实现许可证管理自动化
大数据·数据库·人工智能·adobe·金融·自动化·区块链
小明的小名叫小明14 小时前
Compound协议(2)
区块链·defi
DICOM医学影像17 小时前
1. Remix编写、编译、部署、测试Solidity ERC20合约 - 基础篇
区块链·智能合约·solidity·以太坊·remix·web3.0·erc20
DICOM医学影像1 天前
3. Metamask导入代币,转账ETH,转账代币
区块链·智能合约·solidity·以太坊·metamask·web3.0·erc20
DICOM医学影像1 天前
5. Hardhat编写、编译、部署、测试Solidity ERC20合约 - 进阶篇 - web3.js调用合约方法
区块链·solidity·以太坊·web3.js·hardhat·erc20
小明的小名叫小明1 天前
Compound协议(1)
区块链·defi
virtual_k1smet2 天前
梧桐·鸿鹄-中移链assistant-level
笔记·区块链