🖐🏻 免责声明
本教程仅供学习交流使用,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,请各读者自觉遵守相关法律法规。
# 官方文档
RPC文档地址:https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts
验签地址:https://etherscan.io/verifiedSignatures#
# 网络请求封装
// 创建一个专门的 httpUtil.js 文件或者在网络模块中封装
import axios from "axios";
// 创建并配置 Axios 实例
const service = axios.create({
baseURL: "", // 设置基础 URL
timeout: 5000, // 设置超时时间
headers: {
"Content-Type": "application/json",
},
});
// 请求拦截器 - 在请求发出前做处理
service.interceptors.request.use(
(config) => {
// 添加 token 到 headers 中(假设从Vuex中获取)
// const token = store.getters["auth/token"];
// if (token) {
// config.headers.Authorization = `Bearer ${token}`;
// }
// 其他可能的预处理,如处理请求参数等
return config;
},
(error) => {
// 对请求错误做些什么
console.error("请求错误:", error);
Promise.reject(error);
}
);
// 响应拦截器 - 在收到响应后做处理
service.interceptors.response.use(
(response) => {
// console.log(response);
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
if (response.status === 200) {
const res = response.data;
console.log(JSON.stringify(res, null, 2));
return res || {};
} else {
console.log(response.statusText);
return Promise.reject(new Error(response.statusText || "Error"));
}
},
(error) => {
// 对响应错误做处理
console.error("接口异常:", error);
// Message({
// message: error.message,
// type: "error",
// duration: 5 * 1000,
// });
return Promise.reject(error);
}
);
// 定义常用的请求方法
export const get = (url, params) => service.get(url, { params });
export const post = (url, data) => service.post(url, data);
export const put = (url, data) => service.put(url, data);
export const deleteRequest = (url, data) => service.delete(url, { data }); // 注意 DELETE 方法携带数据的方式因后端而异
// ... 其他HTTP方法的封装(如patch, head, options等)
# rpc请求示例
# 区块
# 异步获取客户端版本信息
/**
* 异步获取客户端版本信息
* @param {string} myurl - 请求的URL地址
* @param {object} myparams - 请求携带的参数对象
* @returns {Promise<object>} 返回一个Promise对象,包含服务器响应的结果
*/
async function clientVersion(myurl, chainId) {
const myparams = {
jsonrpc: "2.0",
method: "web3_clientVersion",
params: [],
id: chainId,
};
const result = await post(myurl, myparams);
return result;
}
# 异步获取指定区块链的当前块号
/**
* 异步获取指定区块链的当前块号
* @param {string} myurl - 区块链节点的URL地址
* @param {number} chainId - 区块链的ID,用于指定请求的区块链网络
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为包含块号结果的对象
*/
async function blockNumber(myurl, chainId) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // JSON-RPC版本
method: "eth_blockNumber", // 请求的方法名
params: [], // 方法参数为空
id: chainId, // 请求的唯一标识,这里使用chainId
};
// 向指定URL发送POST请求,等待响应
const result = await post(myurl, myparams);
// 返回获取到的结果
return result;
}
# 根据区块编号异步获取区块信息
/**
* 根据区块编号异步获取区块信息
* @param {string} myurl 目标URL,向该URL发送请求
* @param {string|number} number 区块编号,可以是earliest latest safe finalized pending 或 一个十六进制的blockNumber
* @param {number} chainId 链的ID,用作请求的唯一标识
* @param {boolean} [showDetail=false] 是否显示交易详情,默认为false,即不显示详细交易信息
* @returns {Promise<any>} 返回一个Promise对象,解析后的结果是获取到的区块信息
*/
async function getBlockByNumber(myurl, mynumber, chainId, showDetail = false) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // JSON-RPC版本
method: "eth_getBlockByNumber", // 请求的方法名
params: [mynumber, showDetail], // 第一个参数可以是下面 earliest latest safe finalized pending 或 一个十六进制的blockNumber,第二个参数是个bool,代表是否获取transaction的详细信息
id: chainId, // 请求的唯一标识,这里使用chainId
};
// 向指定URL发送POST请求,等待响应
const result = await post(myurl, myparams);
// 返回获取到的结果
return result;
}
# 通过哈希值异步获取区块信息
/**
* 通过哈希值异步获取区块信息
* @param {string} myurl 目标URL,向该URL发送请求
* @param {string} myhash 区块的哈希值,用于查找特定的区块
* @param {number} chainId 链的ID,用于标识请求的链
* @param {boolean} showDetail 是否显示交易的详细信息,默认为false,即不显示详细信息
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为获取到的区块信息结果
*/
async function getBlockByHash(myurl, myhash, chainId, showDetail = false) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // JSON-RPC版本
method: "eth_getBlockByHash", // 请求的方法名
params: [myhash, showDetail], // 第二个参数是个bool,代表是否获取transaction的详细信息
id: chainId, // 请求的唯一标识,这里使用chainId
};
// 向指定URL发送POST请求,等待响应
const result = await post(myurl, myparams);
// 返回获取到的结果
return result;
}
# 通过块号异步获取区块的交易数量
/**
* 通过块号异步获取区块的交易数量
* @param {string} myurl 目标URL,向该URL发送请求
* @param {number|string} mynumber 块号,可以是数字或字符串形式
* @param {number} chainId 链ID,用作请求的唯一标识
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为获取到的结果对象
*/
async function getBlockTransactionCountByNumber(myurl, mynumber, chainId) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_getBlockTransactionCountByNumber", // 请求的方法名
params: [mynumber], // 请求的参数,这里只传入了一个参数:块号
id: chainId, // 请求的唯一标识,使用chainId
};
// 向指定URL发送POST请求,并等待响应结果
const result = await post(myurl, myparams);
// 返回从服务器获取到的结果
return result;
}
# 通过区块哈希异步获取区块中的交易数量
/**
* 通过区块哈希异步获取区块中的交易数量
* @param {string} myurl 目标URL,用于发送请求
* @param {string} myhash 区块的哈希值
* @param {number} chainId 链的ID,用于标识请求来源
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为获取到的结果对象
*/
async function getBlockTransactionCountByHash(myurl, myhash, chainId) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // JSON-RPC版本
method: "eth_getBlockTransactionCountByHash", // 请求的方法名
params: [myhash],
id: chainId, // 请求的唯一标识,使用chainId
};
// 向指定URL发送POST请求,等待响应
const result = await post(myurl, myparams);
// 返回获取到的结果
return result;
}
# 异步获取账户信息
/**
* 异步获取账户信息
* @param {string} myurl - 请求的URL
* @param {number|string} chainId - 链的ID,用作请求的唯一标识
* @returns {Promise<any>} 返回一个Promise对象,解析后的结果是调用post方法后的返回值
*/
async function getAccounts(myurl, chainId) {
// 构造请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC的版本
method: "eth_accounts", // 请求的方法名,这里是获取账户信息的方法
params: [], // 方法参数为空
id: chainId, // 请求的唯一标识,使用chainId
};
// 使用post方法发送请求,并等待响应
const result = await post(myurl, myparams);
return result; // 返回获取到的结果
}
# 异步获取指定账户在某一区块的余额
/**
* 异步获取指定账户在某一区块的余额。
* @param {string} myurl JSON-RPC服务的URL地址。
* @param {number} chainId 链的ID,用于标识请求的链。
* @param {string} myaccount 需要查询余额的账户地址。
* @param {string} [block="latest"] 需要查询的区块,可选,默认为"latest"(最新区块)。
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为获取到的余额结果。
*/
async function getBalance(myurl, chainId, myaccount, block = "latest") {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_getBalance", // 指定要调用的RPC方法
params: [myaccount, block], // 方法参数,账户地址和区块
id: chainId, // 请求的唯一标识,使用chainId
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result; // 返回从服务器获取的结果
}
# 消息签名
一些弯弯绕绕的知识点参考这里
/**
* 使用指定的账户和消息内容,在给定的区块链网络上进行签名。--亲测只支持本地节点
* 网上很多要构造ethsign参数的,其实不需要,eth_sign内部就已经构造了
* @param {string} myurl - RPC服务器的URL地址。
* @param {number} chainId - 目标区块链的ID。
* @param {string} myaccount - 需要进行签名的账户地址。
* @param {string} mymessage - 需要签名的消息内容。
* @returns {Promise<Object>} 返回从服务器获取的签名结果。
*/
async function ethSign(myurl, chainId, myaccount, mymessage) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_sign", // 指定要调用的RPC方法
params: [myaccount, "0x" + Buffer.from(mymessage, "utf8").toString("hex")],
id: chainId, // 请求的唯一标识,使用chainId
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result; // 返回从服务器获取的结果
}
# 转账签名与发送
eth_signTransaction,eth_sendRawTransaction
/**
* 异步签名交易
* @param {string} myurl - JSON-RPC服务的URL地址
* @param {number} chainId - 链的ID,标识目标区块链网络
* @param {string} from - 发起交易的地址
* @param {string} to - 接收交易的地址
* @param {number} gas - 交易执行所需的gas量
* @param {string} gasPrice - 指定的gas价格
* @param {string|number} value - 交易发送的价值
* @param {...any} params - 额外的参数,可用于扩展或指定其他交易属性
* @returns {Promise<any>} 发送交易后的结果,通常是一个包含签名信息的对象
*/
async function signTransaction(
myurl,
chainId,
from,
to,
gas,
gasPrice,
value,
...params
) {
// 构建将要发送给JSON-RPC服务的请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_signTransaction", // 指定要调用的RPC方法,注意hardhat节点不支持这个方法
params: [
{
from: from,
to: to,
gas: "0x" + gas.toString(16), // 将gas转换为16进制字符串格式
gasPrice: gasPrice,
value: "0x" + value.toString(16), // 将value转换为16进制字符串格式
...params,
},
],
id: chainId, // 请求的唯一标识,这里使用了chainId
};
console.log(myparams);
// 使用post方法发送请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步发送原始交易请求
* @param {string} myurl - 目标URL,用于发送RPC请求
* @param {number} chainId - 链ID,用于标识目标区块链网络
* @param {string} mymessage - 待发送的原始交易信息
* @returns {Promise<any>} 发送交易的结果,是一个Promise对象,解析后包含服务器返回的数据
*/
async function sendRawTransaction(myurl, chainId, mymessage) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_sendRawTransaction", // 指定要调用的RPC方法
params: [mymessage],
id: chainId, // 请求的唯一标识,使用chainId
};
// 使用post方法发送请求并等待响应
const result = await post(myurl, myparams);
return result;
}
async function main(){
const gasPrice = (await ethGasPrice(url, 1337)).result;
const sig = await signTransaction(
url,
1337,
"0x41a2A45041f32396f3b9ac23b43cbadd4B8A0024",
"0xFf9041176691A7bC07703544FaDF494e590162Cc",
21000,
gasPrice,
10000000000000000000 //1ether
).result;
sendRawTransaction(url, 1337, sig);
}
# 转账&合约方法调用&calldata
# to可以是账户,也可以是合约地址
# 这里面可以有个data,是个十六进制,可以是文本消息,如果to是个合约地址,还可以是合约方法调用
- 合约,需要实现fallback方法
- data优先是去匹配合约方法,匹配不到就进fallback方法
# 调用合约方法data生成
使用abi.encodeWithSignature("方法名(参数1类型,参数2类型),参数1,参数2"),具体用法可以参考solidity-abi的用法
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract EncodeWithSignature {
function createMintData(address to, uint256 amount ) public pure returns (bytes memory) {
return abi.encodeWithSignature("mint(address,uint256)", to, amount);
}
function createBalanceOfData(address account) public pure returns (bytes memory) {
return abi.encodeWithSignature("balanceOf(address)",account);
}
}
# 方法又分获取链上数据
用eth_call
{
from:"",
to:"",
data:""
}
# 向链上写数据
用eth_sendTransaction
# 代码
/**
* 异步发送交易到区块链网络。
* @param {string} myurl JSON-RPC服务的URL。
* @param {number} chainId 链的ID,用于标识目标区块链网络。
* @param {string} from 发送交易的地址。
* @param {string} to 接收交易的地址。
* @param {number} gas 交易执行所需的gas量。
* @param {string} gasPrice 交易的gas价格。
* @param {string|number} value 交易发送的金额。
* @param {...any} params 可选参数,用于扩展或提供额外的交易信息。
* @returns {Promise<any>} 发送交易的结果,是一个Promise对象。
*/
async function sendTransaction(
myurl,
chainId,
from,
to,
gas,
gasPrice,
value,
...params
) {
// 构建JSON-RPC请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_sendTransaction", // 指定调用的RPC方法,获取链上数据用eth_call(这时只需要from,to,data三个参数)
params: [
{
from: from,
to: to,
gas: "0x" + gas.toString(16), // 将gas转换为16进制字符串
gasPrice: gasPrice,
value: "0x" + value.toString(16), // 将value转换为16进制字符串
...params,// 这里面可以有个data,是个十六进制,可以是文本消息,如果to是个合约地址,还可以是合约方法调用
},
],
id: chainId, // 使用chainId作为请求的ID
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步获取交易收据
* @param {string} myurl - 目标URL,用于发送RPC请求
* @param {number} chainId - 链ID,用作请求的唯一标识
* @param {string} mymessage - 交易信息,通常是交易的hash
* @returns {Promise<object>} 返回一个承诺(Promise),解析为RPC调用的结果
*/
async function getTransactionReceipt(myurl, chainId, mymessage) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_getTransactionReceipt", // 指定要调用的RPC方法
params: [mymessage],
id: chainId, // 请求的唯一标识,使用chainId
};
// 使用post方法发送请求并等待响应
const result = await post(myurl, myparams);
return result;
}
async function main(){
const gasPrice = (await ethGasPrice(url, 1337)).result;
sendTransaction(
url,
1337,
"0x41a2A45041f32396f3b9ac23b43cbadd4B8A0024",
"0xFf9041176691A7bC07703544FaDF494e590162Cc",
21000,
gasPrice,
10000000000000000000 //1ether
);
getTransactionReceipt(
url,
1337,
"0x5fc66baf5d9e3c80ea8716f3f583939388afd741fae6f70e7fd6ec6993c41b7a"
);
}
# 评估 Gas
参数构造原理同eth_sendTransaction及eth_call
评估气时和data关系比较大,且0耗气小,非0耗气大,0x00占4个气,0xA0占16个气,0xA0A0占32个气,可以自己多试试
/**
* 异步估计Gas消耗的函数
* @param {string} myurl JSON-RPC服务的URL地址
* @param {number} chainId 链的ID,用于标识目标区块链网络
* @param {string} from 发送交易的地址
* @param {string} to 接收交易的地址
* @param {BigNumber} value 交易发送的价值,需要是一个BigNumber实例,将被转换为十六进制格式
* @param {string} data 交易的数据部分,通常包含智能合约调用的指令
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为RPC响应结果对象
*/
async function estimateGas(myurl, chainId, from, to, value, data) {
// 构建JSON-RPC请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_estimateGas", // 指定调用的RPC方法
params: [
{
from: from,
to: to,
value: "0x" + value.toString(16), // 将value转换为16进制字符串
data: data,
},
],
id: chainId, // 使用chainId作为请求的ID
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
# Filter 日志过滤器
所有的日志,建议先学习Solidity的Event
topics参数可以灵活组合
- [] 查所有
- ["0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c"] 知道第一个topic
- [null,"0x000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88"]知道第二个topic参数
/**
* 异步创建一个新的过滤器,用于订阅特定合约的事件日志。
* @param {string} myurl JSON-RPC服务的URL。
* @param {number} chainId 链的ID,用于标识目标区块链网络。
* @param {number} fromBlock 开始区块的高度,"0x"前缀可省略。
* @param {number} toBlock 结束区块的高度,"0x"前缀可省略。
* @param {string} contractAddress 合约的地址,16进制表示,无需"0x"前缀。
* @param {Array<string>} topics 关注的主题,可以为空数组。每个主题是事件日志的一个过滤条件。
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为RPC调用的结果。
*/
async function newFilter(
myurl,
chainId,
fromBlock,
toBlock,
contractAddress,
topics
) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC版本
method: "eth_newFilter", // 指定要调用的RPC方法名
params: [
// 构建过滤器参数
{
fromBlock: fromBlock ? "0x" + fromBlock.toString(16) : null, // 转换区块高度为16进制字符串
toBlock: toBlock ? "0x" + toBlock.toString(16) : null, // 同上
address: contractAddress, // 目标合约地址
topics: topics, // 关注的主题列表
},
],
id: chainId, // 使用链ID作为请求ID
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步获取过滤后的日志
* @param {string} myurl - 目标URL,用于发送RPC请求
* @param {number|string} chainId - 链的ID,用作请求的唯一标识
* @param {string} mymessage - 用于过滤日志的消息参数
* @returns {Promise<any>} - 返回一个Promise,解析后的结果是RPC调用的响应数据
*/
async function getFilterLogs(myurl, chainId, mymessage) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_getFilterLogs", // 指定要调用的RPC方法
params: [mymessage], // 请求参数
id: chainId, // 请求的唯一标识使用chainId
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
function main(){
const filterID = (
await newFilter(
url,
1,
19665112,
19665112,
"0xB2f8b3Bad4325C3C62f294dA45FC144B1B180CC2",//这里传的合约地址
[]//topic这里不传,就查该合约所有地址所有,也可以灵活组合比如["0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c"] 或 [null,"0x000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88"]等
)
).result;
getFilterLogs(url, 1, filterID);
}
// 返回结果
{
"jsonrpc": "2.0",
"id": 1,
"result": "0xddad60e9e8f34e2af15ec5fb9752b6dc"
}
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"address": "0xb2f8b3bad4325c3c62f294da45fc144b1b180cc2",
"topics": [
"0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c",
"0x000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88",
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb1950",
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb7710"
],
"data": "0x0000000000000000000000000000000000000000000000000000000566c74d910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164c",
"blockNumber": "0x12c10d8",
"transactionHash": "0xdad9d00d532eb759bab7bd39910881c23bcae6c063a14c8f2d46ef5c0d5fb1d5",
"transactionIndex": "0x65",
"blockHash": "0x6c88bf6adba152a6452c316d8aaca42b232a3a9af17d7ad2b0b81ae19efaf585",
"logIndex": "0xf3",
"removed": false
},
{
"address": "0xb2f8b3bad4325c3c62f294da45fc144b1b180cc2",
"topics": [
"0x70935338e69775456a85ddef226c395fb668b63fa0115f5f20610b388e6ca9c0",
"0x000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88",
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb1950",
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb7710"
],
"data": "0x000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe880000000000000000000000000000000000000000000000000032a520ac387fee0000000000000000000000000000000000000000000000000000000000001a7a",
"blockNumber": "0x12c10d8",
"transactionHash": "0xdad9d00d532eb759bab7bd39910881c23bcae6c063a14c8f2d46ef5c0d5fb1d5",
"transactionIndex": "0x65",
"blockHash": "0x6c88bf6adba152a6452c316d8aaca42b232a3a9af17d7ad2b0b81ae19efaf585",
"logIndex": "0xf7",
"removed": false
}
]
}
# BlockFilter 区块过滤器
/**
* 异步创建一个新的区块过滤器
* @param {string} myurl - 目标RPC服务的URL。
* @param {number|string} chainId - 链的ID,用作请求的唯一标识。
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为RPC调用的结果。
*/
async function newBlockFilter(myurl, chainId) {
// 构建JSON-RPC请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_newBlockFilter", // 指定要调用的RPC方法名称
params: [], // 请求参数为空
id: chainId, // 将链的ID用作请求的唯一标识
};
// 使用提供的URL和参数发送POST请求,并等待响应
const result = await post(myurl, myparams);
// 返回RPC调用的结果
return result;
}
/**
* 异步卸载过滤器
* @param {string} myurl - 目标URL,用于发送RPC请求。
* @param {number} chainId - 链ID,用作RPC请求的唯一标识。
* @param {string} mymessage - 过滤器标识,指定要卸载的过滤器。
* @returns {Promise<Object>} 返回一个Promise,解析后的结果是RPC调用的返回值。
*/
async function uninstallFilter(myurl, chainId, mymessage) {
// 构建JSON-RPC请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_uninstallFilter", // 指定要调用的RPC方法
params: [mymessage], // 请求参数,传入过滤器标识
id: chainId, // 使用链ID作为请求的唯一标识
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
// 返回RPC调用结果
return result;
}
/**
* 异步获取过滤器更新
* @param {string} myurl - 目标URL,用于发送RPC请求
* @param {number|string} chainId - 链ID,用作RPC请求的唯一标识
* @param {string} mymessage - 过滤器标识,用于指定要获取更新的过滤器
* @returns {Promise<any>} 返回一个Promise,解析为RPC调用的结果
*/
async function getFilterChanges(myurl, chainId, mymessage) {
// 构建JSON-RPC请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_getFilterChanges", // 指定要调用的RPC方法
params: [mymessage], // 请求参数,传入过滤器标识
id: chainId, // 使用链ID作为请求的唯一标识
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
// 返回RPC调用结果
return result;
}
# 创建区块过滤器,eth_newBlockFilter
参数
{
"jsonrpc": "2.0",
"method": "eth_newBlockFilter",
"params": [],
"id": 1
}
返回值
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x2e7088866bf2d36b48d1ae719da9b565"
}
# 删除订阅/监听区块过滤器,eth_uninstallFilter
参数
{
"jsonrpc": "2.0",
"method": "eth_uninstallFilter",
"params": ["0x2e7088866bf2d36b48d1ae719da9b565"],
"id": 1
}
返回值
{
"jsonrpc": "2.0",
"id": 1,
"result": true
}
# 订阅/监听区块过滤器,eth_getfilterchanges
可以监听eth_newBlockFilter 和 eth_newFilter得到的那个id
//参数
{
"jsonrpc": "2.0",
"method": "eth_getFilterChanges",
"params": ["0x2e7088866bf2d36b48d1ae719da9b565"],
"id": 1
}
//返回值
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"0x845bed3a0bf3f4d784d6aa39d3b9fe44d91e9bac5f978b14d123d463b479fab7",
"0xa73b8021913c310e20a4553e3f60799d6074f5bdf31730f6ccc0178662677753",
"0xb660573b6fbc1f33eebcd6e0fd231ab7b5f85b94d0b2c4bd2becbf5bc5708f6b",
"0x52e4942e83dd252c6ab678d242d25613f9c74604362d4af1270e1d90c01d939c"
]
}
# 案例-监听uniswap某个合约对的swap方法被调用及USDC的转账事件
# TransactionFilter 交易过滤器
/**
* 异步创建一个新的待处理交易过滤器
* @param {string} myurl - JSON-RPC服务的URL。
* @param {number} chainId - 链的ID,用作请求的唯一标识。
* @returns {Promise<Object>} 返回RPC调用的结果,是一个承诺(Promise)。
*/
async function newPendingTransactionFilter(myurl, chainId) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_newPendingTransactionFilter", // 指定要调用的RPC方法
params: [], // 请求参数为空
id: chainId, // 使用链的ID作为请求的标识符
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
// 返回RPC调用结果
return result;
}
# Logs 查询事件日志
等于是Filter 日志过滤器的两个方法结合使用
如果有blockhash参数,那么fromBlock与toBlock 参数将被忽略掉
/**
* 异步获取区块链日志-注意,如果有blockhash参数,那么fromBlock与toBlock 参数将被忽略掉
*
* @param {string} myurl RPC服务的URL地址
* @param {number} chainId 链的ID
* @param {number} fromBlock 起始区块高度(可选)
* @param {number} toBlock 结束区块高度(可选)
* @param {string} contractAddress 目标合约的地址
* @param {Array<string>} topics 关注的主题列表(可选)
* @param {string} blockHash 指定区块的哈希值(可选)
* @returns {Promise<any>} 返回日志结果的Promise对象
*/
async function getLogs(
myurl,
chainId,
fromBlock,
toBlock,
contractAddress,
topics,
blockHash
) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC版本
method: "eth_getLogs", // 指定要调用的RPC方法名
params: [
// 构建过滤器参数
{
fromBlock: fromBlock ? "0x" + fromBlock.toString(16) : null, // 转换区块高度为16进制字符串,未指定则为null
toBlock: toBlock ? "0x" + toBlock.toString(16) : null, // 同上
address: contractAddress, // 目标合约地址
topics: topics, // 关注的主题列表
blockHash: blockHash, // 指定区块的哈希值
},
],
id: chainId, // 使用链ID作为请求ID
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
# 完整代码
// 引入 axios 库
import { post } from "./httpUtil.js";
// RPC文档地址:https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts
// 验签地址:https://etherscan.io/verifiedSignatures#
/**
* 异步获取客户端版本信息
* @param {string} myurl - 请求的URL地址
* @param {object} myparams - 请求携带的参数对象
* @returns {Promise<object>} 返回一个Promise对象,包含服务器响应的结果
*/
async function clientVersion(myurl, chainId) {
const myparams = {
jsonrpc: "2.0",
method: "web3_clientVersion",
params: [],
id: chainId,
};
const result = await post(myurl, myparams);
return result;
}
/**
* 异步获取指定区块链的当前块号
* @param {string} myurl - 区块链节点的URL地址
* @param {number} chainId - 区块链的ID,用于指定请求的区块链网络
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为包含块号结果的对象
*/
async function blockNumber(myurl, chainId) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // JSON-RPC版本
method: "eth_blockNumber", // 请求的方法名
params: [], // 方法参数为空
id: chainId, // 请求的唯一标识,这里使用chainId
};
// 向指定URL发送POST请求,等待响应
const result = await post(myurl, myparams);
// 返回获取到的结果
return result;
}
/**
* 根据区块编号异步获取区块信息
* @param {string} myurl 目标URL,向该URL发送请求
* @param {string|number} number 区块编号,可以是earliest latest safe finalized pending 或 一个十六进制的blockNumber
* @param {number} chainId 链的ID,用作请求的唯一标识
* @param {boolean} [showDetail=false] 是否显示交易详情,默认为false,即不显示详细交易信息
* @returns {Promise<any>} 返回一个Promise对象,解析后的结果是获取到的区块信息
*/
async function getBlockByNumber(myurl, mynumber, chainId, showDetail = false) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // JSON-RPC版本
method: "eth_getBlockByNumber", // 请求的方法名
params: [mynumber, showDetail], // 第一个参数可以是下面 earliest latest safe finalized pending 或 一个十六进制的blockNumber,第二个参数是个bool,代表是否获取transaction的详细信息
id: chainId, // 请求的唯一标识,这里使用chainId
};
// 向指定URL发送POST请求,等待响应
const result = await post(myurl, myparams);
// 返回获取到的结果
return result;
}
/**
* 通过哈希值异步获取区块信息
* @param {string} myurl 目标URL,向该URL发送请求
* @param {string} myhash 区块的哈希值,用于查找特定的区块
* @param {number} chainId 链的ID,用于标识请求的链
* @param {boolean} showDetail 是否显示交易的详细信息,默认为false,即不显示详细信息
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为获取到的区块信息结果
*/
async function getBlockByHash(myurl, myhash, chainId, showDetail = false) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // JSON-RPC版本
method: "eth_getBlockByHash", // 请求的方法名
params: [myhash, showDetail], // 第二个参数是个bool,代表是否获取transaction的详细信息
id: chainId, // 请求的唯一标识,这里使用chainId
};
// 向指定URL发送POST请求,等待响应
const result = await post(myurl, myparams);
// 返回获取到的结果
return result;
}
/**
* 通过块号异步获取区块的交易数量
* @param {string} myurl 目标URL,向该URL发送请求
* @param {number|string} mynumber 块号,可以是数字或字符串形式
* @param {number} chainId 链ID,用作请求的唯一标识
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为获取到的结果对象
*/
async function getBlockTransactionCountByNumber(myurl, mynumber, chainId) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_getBlockTransactionCountByNumber", // 请求的方法名
params: [mynumber], // 请求的参数,这里只传入了一个参数:块号
id: chainId, // 请求的唯一标识,使用chainId
};
// 向指定URL发送POST请求,并等待响应结果
const result = await post(myurl, myparams);
// 返回从服务器获取到的结果
return result;
}
/**
* 通过区块哈希异步获取区块中的交易数量
* @param {string} myurl 目标URL,用于发送请求
* @param {string} myhash 区块的哈希值
* @param {number} chainId 链的ID,用于标识请求来源
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为获取到的结果对象
*/
async function getBlockTransactionCountByHash(myurl, myhash, chainId) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // JSON-RPC版本
method: "eth_getBlockTransactionCountByHash", // 请求的方法名
params: [myhash],
id: chainId, // 请求的唯一标识,使用chainId
};
// 向指定URL发送POST请求,等待响应
const result = await post(myurl, myparams);
// 返回获取到的结果
return result;
}
/**
* 异步获取账户信息
* @param {string} myurl - 请求的URL
* @param {number|string} chainId - 链的ID,用作请求的唯一标识
* @returns {Promise<any>} 返回一个Promise对象,解析后的结果是调用post方法后的返回值
*/
async function getAccounts(myurl, chainId) {
// 构造请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC的版本
method: "eth_accounts", // 请求的方法名,这里是获取账户信息的方法
params: [], // 方法参数为空
id: chainId, // 请求的唯一标识,使用chainId
};
// 使用post方法发送请求,并等待响应
const result = await post(myurl, myparams);
return result; // 返回获取到的结果
}
/**
* 异步获取指定账户在某一区块的余额。
* @param {string} myurl JSON-RPC服务的URL地址。
* @param {number} chainId 链的ID,用于标识请求的链。
* @param {string} myaccount 需要查询余额的账户地址。
* @param {string} [block="latest"] 需要查询的区块,可选,默认为"latest"(最新区块)。
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为获取到的余额结果。
*/
async function getBalance(myurl, chainId, myaccount, block = "latest") {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_getBalance", // 指定要调用的RPC方法
params: [myaccount, block], // 方法参数,账户地址和区块
id: chainId, // 请求的唯一标识,使用chainId
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result; // 返回从服务器获取的结果
}
/**
* 使用指定的账户和消息内容,在给定的区块链网络上进行签名。--亲测只支持本地节点
* @param {string} myurl - RPC服务器的URL地址。
* @param {number} chainId - 目标区块链的ID。
* @param {string} myaccount - 需要进行签名的账户地址。
* @param {string} mymessage - 需要签名的消息内容。
* @returns {Promise<Object>} 返回从服务器获取的签名结果。
*/
async function ethSign(myurl, chainId, myaccount, mymessage) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_sign", // 指定要调用的RPC方法
params: [myaccount, "0x" + Buffer.from(mymessage, "utf8").toString("hex")],
id: chainId, // 请求的唯一标识,使用chainId
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result; // 返回从服务器获取的结果
}
/**
* 异步签名交易
* @param {string} myurl - JSON-RPC服务的URL地址
* @param {number} chainId - 链的ID,标识目标区块链网络
* @param {string} from - 发起交易的地址
* @param {string} to - 接收交易的地址
* @param {number} gas - 交易执行所需的gas量
* @param {string} gasPrice - 指定的gas价格
* @param {string|number} value - 交易发送的价值
* @param {...any} params - 额外的参数,可用于扩展或指定其他交易属性
* @returns {Promise<any>} 发送交易后的结果,通常是一个包含签名信息的对象
*/
async function signTransaction(
myurl,
chainId,
from,
to,
gas,
gasPrice,
value,
...params
) {
// 构建将要发送给JSON-RPC服务的请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_signTransaction", // 指定要调用的RPC方法,注意hardhat节点不支持这个方法
params: [
{
from: from,
to: to,
gas: "0x" + gas.toString(16), // 将gas转换为16进制字符串格式
gasPrice: gasPrice,
value: "0x" + value.toString(16), // 将value转换为16进制字符串格式
...params,
},
],
id: chainId, // 请求的唯一标识,这里使用了chainId
};
console.log(myparams);
// 使用post方法发送请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步发送原始交易请求
* @param {string} myurl - 目标URL,用于发送RPC请求
* @param {number} chainId - 链ID,用于标识目标区块链网络
* @param {string} mymessage - 待发送的原始交易信息
* @returns {Promise<any>} 发送交易的结果,是一个Promise对象,解析后包含服务器返回的数据
*/
async function sendRawTransaction(myurl, chainId, mymessage) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_sendRawTransaction", // 指定要调用的RPC方法
params: [mymessage],
id: chainId, // 请求的唯一标识,使用chainId
};
// 使用post方法发送请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步发送交易到区块链网络。
* @param {string} myurl JSON-RPC服务的URL。
* @param {number} chainId 链的ID,用于标识目标区块链网络。
* @param {string} from 发送交易的地址。
* @param {string} to 接收交易的地址。
* @param {number} gas 交易执行所需的gas量。
* @param {string} gasPrice 交易的gas价格。
* @param {string|number} value 交易发送的金额。
* @param {...any} params 可选参数,用于扩展或提供额外的交易信息。
* @returns {Promise<any>} 发送交易的结果,是一个Promise对象。
*/
async function sendTransaction(
myurl,
chainId,
from,
to,
gas,
gasPrice,
value,
...params
) {
// 构建JSON-RPC请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_sendTransaction", // 指定调用的RPC方法,获取链上数据用eth_call(这时只需要from,to,data三个参数)
params: [
{
from: from,
to: to,
gas: "0x" + gas.toString(16), // 将gas转换为16进制字符串
gasPrice: gasPrice,
value: "0x" + value.toString(16), // 将value转换为16进制字符串
...params,// 这里面可以有个data,是个十六进制,可以是文本消息,如果to是个合约地址,还可以是合约方法调用
},
],
id: chainId, // 使用chainId作为请求的ID
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步获取交易收据
* @param {string} myurl - 目标URL,用于发送RPC请求
* @param {number} chainId - 链ID,用作请求的唯一标识
* @param {string} mymessage - 交易信息,通常是交易的hash
* @returns {Promise<object>} 返回一个承诺(Promise),解析为RPC调用的结果
*/
async function getTransactionReceipt(myurl, chainId, mymessage) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC协议版本
method: "eth_getTransactionReceipt", // 指定要调用的RPC方法
params: [mymessage],
id: chainId, // 请求的唯一标识,使用chainId
};
// 使用post方法发送请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步估计Gas消耗的函数
* @param {string} myurl JSON-RPC服务的URL地址
* @param {number} chainId 链的ID,用于标识目标区块链网络
* @param {string} from 发送交易的地址
* @param {string} to 接收交易的地址
* @param {BigNumber} value 交易发送的价值,需要是一个BigNumber实例,将被转换为十六进制格式
* @param {string} data 交易的数据部分,通常包含智能合约调用的指令
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为RPC响应结果对象
*/
async function estimateGas(myurl, chainId, from, to, value, data) {
// 构建JSON-RPC请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_estimateGas", // 指定调用的RPC方法
params: [
{
from: from,
to: to,
value: "0x" + value.toString(16), // 将value转换为16进制字符串
data: data,
},
],
id: chainId, // 使用chainId作为请求的ID
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步创建一个新的过滤器,用于订阅特定合约的事件日志。
* @param {string} myurl JSON-RPC服务的URL。
* @param {number} chainId 链的ID,用于标识目标区块链网络。
* @param {number} fromBlock 开始区块的高度,"0x"前缀可省略。
* @param {number} toBlock 结束区块的高度,"0x"前缀可省略。
* @param {string} contractAddress 合约的地址,16进制表示,无需"0x"前缀。
* @param {Array<string>} topics 关注的主题,可以为空数组。每个主题是事件日志的一个过滤条件。
* @returns {Promise<Object>} 返回一个承诺(Promise),解析为RPC调用的结果。
*/
async function newFilter(
myurl,
chainId,
fromBlock,
toBlock,
contractAddress,
topics
) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC版本
method: "eth_newFilter", // 指定要调用的RPC方法名
params: [
// 构建过滤器参数
{
fromBlock: fromBlock ? "0x" + fromBlock.toString(16) : null, // 转换区块高度为16进制字符串
toBlock: toBlock ? "0x" + toBlock.toString(16) : null, // 同上
address: contractAddress, // 目标合约地址
topics: topics, // 关注的主题列表
},
],
id: chainId, // 使用链ID作为请求ID
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步获取过滤后的日志
* @param {string} myurl - 目标URL,用于发送RPC请求
* @param {number|string} chainId - 链的ID,用作请求的唯一标识
* @param {string} mymessage - 用于过滤日志的消息参数
* @returns {Promise<any>} - 返回一个Promise,解析后的结果是RPC调用的响应数据
*/
async function getFilterLogs(myurl, chainId, mymessage) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_getFilterLogs", // 指定要调用的RPC方法
params: [mymessage], // 请求参数
id: chainId, // 请求的唯一标识使用chainId
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
/**
* 异步创建一个新的待处理交易过滤器
* @param {string} myurl - JSON-RPC服务的URL。
* @param {number} chainId - 链的ID,用作请求的唯一标识。
* @returns {Promise<Object>} 返回RPC调用的结果,是一个承诺(Promise)。
*/
async function newPendingTransactionFilter(myurl, chainId) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定JSON-RPC协议版本
method: "eth_newPendingTransactionFilter", // 指定要调用的RPC方法
params: [], // 请求参数为空
id: chainId, // 使用链的ID作为请求的标识符
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
// 返回RPC调用结果
return result;
}
/**
* 异步获取区块链日志-注意,如果有blockhash参数,那么fromBlock与toBlock 参数将被忽略掉
*
* @param {string} myurl RPC服务的URL地址
* @param {number} chainId 链的ID
* @param {number} fromBlock 起始区块高度(可选)
* @param {number} toBlock 结束区块高度(可选)
* @param {string} contractAddress 目标合约的地址
* @param {Array<string>} topics 关注的主题列表(可选)
* @param {string} blockHash 指定区块的哈希值(可选)
* @returns {Promise<any>} 返回日志结果的Promise对象
*/
async function getLogs(
myurl,
chainId,
fromBlock,
toBlock,
contractAddress,
topics,
blockHash
) {
// 构建请求参数
const myparams = {
jsonrpc: "2.0", // 指定使用的JSON-RPC版本
method: "eth_getLogs", // 指定要调用的RPC方法名
params: [
// 构建过滤器参数
{
fromBlock: fromBlock ? "0x" + fromBlock.toString(16) : null, // 转换区块高度为16进制字符串,未指定则为null
toBlock: toBlock ? "0x" + toBlock.toString(16) : null, // 同上
address: contractAddress, // 目标合约地址
topics: topics, // 关注的主题列表
blockHash: blockHash, // 指定区块的哈希值
},
],
id: chainId, // 使用链ID作为请求ID
};
// 发送POST请求并等待响应
const result = await post(myurl, myparams);
return result;
}
const url =
"";
async function main() {
// clientVersion(url, 1);
// blockNumber(url, 1);
// console.log(parseInt("0x12b7021", 16));
// getBlockByNumber(url, "0x12b71a7", 1, false);
// getBlockByHash(
// url,
// "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
// 1,
// false
// );
// getBlockTransactionCountByNumber(url, "0x12b71a7", 1);
// getBlockTransactionCountByHash(
// url,
// "0x15afc4b3c5b61345bebe9d9ab387b386a8a57dbdabc86eddc344986db53c8328",
// 1
// );
// getAccounts(url, 1);
// getBalance(url, 1, "address", "latest");
// 0x8b52e5fc03e6438c99ec12dabc8d842d991a6c7235f08ea01ff8220685628322
// const gasPrice = (await ethGasPrice(url, 1337)).result;
// const sig = await signTransaction(
// url,
// 1337,
// "0x41a2A45041f32396f3b9ac23b43cbadd4B8A0024",
// "0xFf9041176691A7bC07703544FaDF494e590162Cc",
// 21000,
// gasPrice,
// 10000000000000000000 //1ether
// ).result;
// sendRawTransaction(url, 1337, sig);
// sendTransaction(
// url,
// 1337,
// "0x41a2A45041f32396f3b9ac23b43cbadd4B8A0024",
// "0xFf9041176691A7bC07703544FaDF494e590162Cc",
// 21000,
// gasPrice,
// 10000000000000000000 //1ether
// );
// getTransactionReceipt(
// url,
// 1337,
// "0x5fc66baf5d9e3c80ea8716f3f583939388afd741fae6f70e7fd6ec6993c41b7a"
// );
// const filterID = (
// await newFilter(
// url,
// 1,
// 19665112,
// 19665112,
// "0xB2f8b3Bad4325C3C62f294dA45FC144B1B180CC2",
// []
// )
// ).result;
// getFilterLogs(url, 1, filterID);
}
main();

