Viem 對於 "public" Ethereum RPC 定義了一些動作可以使用
會分為二個章節說明:
先來點基礎的
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
export const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});
// 取得帳號餘額
const balance = await publicClient.getBalance({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
});
console.log(balance);
// 9065643223449644n
// 取得事務數
const transactionCount = await publicClient.getTransactionCount({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
});
console.log(transactionCount);
// 113
// https://etherscan.io/txs?a=0xA0Cf798816D4b9b9866b5330EEa46a18382f251e&f=2
程式實作:
https://github.com/0xRory/ITHepleViem/blob/main/examples/3_1_pulbicAction_Account.js
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
export const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});
// 取得目前 block
const block = await publicClient.getBlock();
// 取得目前區塊交易數
const count = await publicClient.getBlockTransactionCount();
// 監聽 BlockNumber
const unwatchBlockNumber = publicClient.watchBlockNumber({
onBlockNumber: (blockNumber) => console.log(blockNumber),
});
// 監聽 Block
const unwatchBlock = publicClient.watchBlocks({
onBlock: (block) => console.log(block),
});
// 取得目前的區塊鏈ID
const chainId = await publicClient.getChainId()
這邊簡單介紹提供的方法,其實 Viem 他整合了監聽還蠻好用的你不用再自己寫。
程式實作:
https://github.com/0xRory/ITHepleViem/blob/main/examples/3_2_publicAction_Block.js
我個人覺得這個是很重要的
下列也是使用代碼來說明:
import { createPublicClient, http, parseEther } from 'viem';
import { mainnet } from 'viem/chains';
export const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});
// 估算每單位燃料價格
// maxPriorityFeePerGas 每單位燃料的優先價格上限
// maxFeePerGas 每單位燃料的價格上限
const { maxFeePerGas, maxPriorityFeePerGas } =
await publicClient.estimateFeesPerGas();
/**
* {
* maxFeePerGas: 19_788_646_562n,
* maxPriorityFeePerGas: 50_000_000n,
* }
*/
console.log({ maxFeePerGas, maxPriorityFeePerGas });
// gasPrice 估計每單位燃料價錢
const { gasPrice } = await publicClient.estimateFeesPerGas({
type: 'legacy',
});
/**
* { gasPrice: 19_788_646_562n }
*/
console.log({ gasPrice });
// 可以參考這篇文章(大前輩)
// https://ithelp.ithome.com.tw/articles/10293790?sc=iThelpR
// export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266';
// // 估計消耗 Gas
// const gasEstimate = await publicClient.estimateGas({
// account,
// to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
// value: parseEther('1'),
// });
// 不過因該會出現錯誤,因為錢包沒錢
// insufficient funds for gas * price + value: address 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 have 0 want 1000000000000000000
// 取得歷史費用
const feeHistory = await publicClient.getFeeHistory({
blockCount: 4,
rewardPercentiles: [25, 75],
});
console.log(feeHistory);
程式實作:
https://github.com/0xRory/ITHepleViem/blob/main/examples/3_3_publicAction_Fee.js
先提前說明一下,這些方法還是要看您連線的 RPC_URL
是否有提供這些功能
這裡分為幾個方法
建立篩選、呈現結果、監控事件、釋放篩選
建立篩選 Filters 大致可分為
呈現結果
如果你是使用
createBlockFilter
createContractEventFilter
createEventFilter
createPendingTransactionFilter
這些方法的話都要用 getFilterChanges
去呈現
import { createPublicClient, http, parseAbiItem } from 'viem';
import { mainnet } from 'viem/chains';
const transport = http('https://ethereum-mainnet-rpc.allthatnode.com');
export const publicClient = createPublicClient({
chain: mainnet,
transport: transport,
});
// 監聽新區塊的篩選
const filterBlock = await publicClient.createBlockFilter();
const hashes = await publicClient.getFilterChanges({ filterBlock })
// ["0x10d86dc08ac2f18f00ef0daf7998dcc8673cbcf1f1501eeb2fac1afd2f851128", ...]
// 我測試了很多 public rpc 是沒測試出來
// 監聽事件
const filterEvent = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // 地址
event: parseAbiItem(
'event Transfer(address indexed from, address indexed to, uint256 value)'
), // 監控的 event
fromBlock: 16330000n, // 開始篩選
toBlock: 16330050n, // 結束篩選
});
const EventLogs = await publicClient.getFilterChanges({ filterEvent })
// [{ ... }, { ... }, { ... }]
const filterPendingTx = await publicClient.createPendingTransactionFilter()
const txHashes = await publicClient.getFilterChanges({ filterPendingTx })
// ["0x89b3aa1c01ca4da5d15eca9fab459d062db5c0c9b76609acb0741901f01f6d19", ...]
const logs = await publicClient.getLogs({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem(
'event Transfer(address indexed, address indexed, uint256)'
),
args: {
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
},
fromBlock: 16330001n,
toBlock: 16330001n,
});
console.log(logs.length);
getLogs
找尋紀錄,但請記得是你有呼叫合約 event logs 才找得到的喔
幾點注意的:
event
寫法有很多種,個人是比較喜歡這樣的寫法,可參考
args
只有在屬性有設定 indexed
才可以使控制喔fromBlock
和 toBlock
不能和 args
共用 (我自己測試是這樣拉)程式實作:
https://github.com/0xRory/ITHepleViem/blob/main/examples/3_4_publicAction_Filter.js
今天寫好多啊~自己覺得這幾個都還蠻重要的。
參考:
https://viem.sh/docs/actions/public/createBlockFilter.html
https://viem.sh/docs/actions/public/createEventFilter.html
https://viem.sh/docs/actions/public/getFilterChanges.html
https://ithelp.ithome.com.tw/articles/10293790?sc=iThelpR
https://viem.sh/docs/actions/public/watchBlocks.html
https://viem.sh/docs/actions/public/getLogs.html