Published: 20 Nov 2023 › Updated: 20 Nov 2023
ethers.js与合约交互及事件机制 / 学习智能合约#66
上次测试了ethers.js与链上的交互功能,这次测试下与合约的交互以及查看事件的机制。这次也是准备打通链上与AI·Joe的功能:充值与NFT。预备着过几天上线新功能。
与合约交互
//只读方法 (like view and pure)
import { ethers } from 'ethers'
//const url = "http://127.0.0.1:8545"
// const url = "https://polygon-rpc.com"
const url = "https://rpc-mumbai.maticvigil.com"
const provider = new ethers.JsonRpcProvider(url)
let abi = [
"function str() view returns (string)",
"function set(uint x)",
"function get()view returns (uint)"
]
//这里的abi相当于接口
// 也可以使用合约的编译abi: import Storage from '@/static/Storage.json' -> Storage.abi
let contractAddr = "0x600a00aE84b896edd9F2732565cf2195d032315E"
let contract = new ethers.Contract(contractAddr, abi, provider)
let str = await contract.get()
console.log(256, str)
//合约的所有方法, signer签名 metamask
const url = "http://127.0.0.1:8545"
const contractAddr = "0x600a00aE84b896edd9F2732565cf2195d032315E"
const provider = new ethers.JsonRpcProvider(url)
const signer = await provider.getSigner()
const contract = new ethers.Contract( contractAddr, Storage.abi, signer)
console.log(56, "signer:", signer)
const option = {
}
const tx = await contract.set(996, option)
await tx.wait()
console.log(669, "singen res:", tx)
//合约的set方法, 需要连上钱包来实现
import Storage from '@/static/Storage.json'
const url = "http://127.0.0.1:8545"
const contractAddr = "0x600a00aE84b896edd9F2732565cf2195d032315E"
const provider = new ethers.JsonRpcProvider(url)
const contract = new ethers.Contract(contractAddr, Storage.abi, provider)
const PRIVATE_KEY = "0x182xxxxxxxxx"
const wallet = new ethers.Wallet(PRIVATE_KEY, provider)
console.log(56, "wallet:", wallet)
const nonce = await provider.getTransactionCount(wallet.address)
console.log(58, "nonce:", nonce)
const StorageConnected = contract.connect(wallet)
const option = {
nonce
}
const tx = await StorageConnected.set(86394, option)
await tx.wait()
console.log(669, "res:", tx)
//另一种写法 在创建合约实例时导入钱包
const privateKey = 'bde95xxxxx'
const wallet = new ethers.Wallet(privateKey, provider)
console.log(56, "wallet:", wallet)
const _Contract = new ethers.Contract(contractAddr, ContractAbi, wallet)
const main = async () => {
//显示原本的 owner
let ownerVal = await _Contract.getOwner()
console.log("原本的 owner:", ownerVal)
//调用 setOwner 更改 owner
await _Contract.setOwner("0x503063dD8f114059B09FD5bC953E71fc14a1d672")
//更改后的 owner
ownerVal = await _Contract.getOwner()
console.log("更改后的 owner:", ownerVal)
}
main()
友好的abi
在上一点中,我们使用的 abi 并不是非常友好,咱们编写 abi 还有一种比较简单的 函数签名的方式 编写abi:
const ContractAbi = [
"function getOwner()view public returns(address)",
]
其实简单点来说你就把函数签名进行复制过来就ok了,由于我们只是一个只读合约,复制一个只读方法即可,这样也可以完成上一点的内容。
eg:
const abi = [
"event Transfer(address indexed from, address indexed to, uint value)",
"function balanceOf(address account) external view returns (uint256)",
"function transfer(address recipient, uint256 amount) external returns (bool)"
]
读取合约历史事件
查询合约的历史数据通常涉及到查看合约发出的事件(events),queryFilter来查询
import { ethers } from "ethers"
const url = "https://rpc-mumbai.maticvigil.com"
const provider = new ethers.JsonRpcProvider(url)
const abi = [
"event Transfer(address indexed from, address indexed to, uint value)"
]
const address = '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c'
const contract = new ethers.Contract(address, abi, provider)
// Query the last 1000 blocks for any transfer
let filter = contract.filters.Transfer
let events = await contract.queryFilter(filter, -1000)
//也可以这样写
// const height = await provider.getBlockNumber()
// const events = await contract.queryFilter('Transfer', height - 1000, height)
console.log(899, "events", events)
//
[
EventLog {
provider: JsonRpcProvider {},
transactionHash: '0x3ca891c7df6ce814e7a418bf1b6985ff88ec2087f540665c752a1916e0982e86',
blockHash: '0xd8b47357bfcf1ae0185e458d393a1a8ba9a19999aa7c16c719edaadc30ad0419',
blockNumber: 42621522,
removed: false,
address: '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c',
data: '0x00000000000000000000000000000000000000000000000ae2a8e81db2700000',
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000654efb5135e61f3db91dd69d239c2e2812d73604',
'0x000000000000000000000000469d135bfdde122a198b978d1a85f05100217246'
],
index: 83,
transactionIndex: 36,
interface: Interface {
fragments: [Array],
deploy: [ConstructorFragment],
fallback: null,
receive: false
},
fragment: EventFragment {
type: 'event',
inputs: [Array],
name: 'Transfer',
anonymous: false
},
args: Result(3) [
'0x654Efb5135E61f3Db91dd69d239c2E2812D73604',
'0x469D135bFdDe122a198B978d1A85f05100217246',
200800000000000000000n
]
}
]
获取历史日志
getLogs方法获取历史日志
let contractEnsName = '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c'
let topic = ethers.id("Transfer(address,address,uint256)")
console.log(123, topic)
let filter = {
address: contractEnsName,
fromBlock: -600,
toBlock: 'latest',
topics: [ topic ]
}
let result = await provider.getLogs(filter)
console.log(6663, result)
//
[ Log {
provider: JsonRpcProvider {},
transactionHash: '0x8736cd74cb13488df6b49899cd8833206e003c37f02560a92c0ac9495c7155c5',
blockHash: '0x5e163f0a62cdc8c858a4aaf2ba6cf471c9abf074fc887d611db64a5005fa8a18',
blockNumber: 42625293,
removed: false,
address: '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c',
data: '0x00000000000000000000000000000000000000000000000029a2241af62c0000',
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x0000000000000000000000003b2dbd900e9b23e94270ade010616b9a28293a87',
'0x000000000000000000000000032f93fae3866af7e86b8022c8ec33b60965de82'
],
index: 21,
transactionIndex: 4
}
]
请注意,查询历史事件可能需要你的提供者支持历史状态查询,这在某些免费提供者中可能是受限的。
如果你需要查询很早之前的事件,可能需要一个归档节点或者使用专门的区块链索引服务,
如 The Graph。此外,查询大量的历史数据可能会非常耗时,并且可能会受到节点服务的速率限制。
在实际应用中,你可能需要考虑分批查询或使用其他策略来优化性能。
事件监听
async function main(){
const abi = [
"event Transfer(address indexed from, address indexed to, uint value)"
]
const address = '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c'
const contract = new ethers.Contract(address, abi, provider)
// Begin listening for any Transfer event
contract.on("Transfer", (from, to, _amount, event) => {
const amount = ethers.formatEther(_amount)
console.log(666, `${ from } => ${ to }: ${ amount }`);
// The `event.log` has the entire EventLog
// Optionally, stop listening
event.removeListener()
})
/*
// Same as above
contract.on(contract.filters.Transfer, (from, to, amount, event) => {
// See above
})
// Listen for any Transfer to "ethers.eth"
filter = contract.filters.Transfer("ethers.eth")
contract.on(filter, (from, to, amount, event) => {
// `to` will always be equal to the address of "ethers.eth"
})
// Listen for any event, whether it is present in the ABI
// or not. Since unknown events can be picked up, the
// parameters are not destructed.
contract.on("*", (event) => {
// The `event.log` has the entire EventLog
})
*/
}
main()
Leave ethers.js与合约交互及事件机制 / 学习智能合约#66 to:
Read more #smartcontract posts
Best Posts From lemooljiang
We have not curated any of lemooljiang's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.
More Posts From lemooljiang
- DeepTutor:AI个性化辅导平台 / ai #57
- ComfyUI:可编程和自动化的PS / ai #56
- 将Neo4j封装进Agent / ai #55
- 闲鱼省钱大法:极限0.5折!
- 对Neo4j批量导入结构化数据 / ai #54
- langchain对neo4j进行交互,写入和查询数据 / ai #53
- 知识图谱和图数据库Neo4j的作用和使用场景 / ai #52
- SpaceX、美股和比特币
- 又是币圈血洗日!
- 链股合流,当币安也开始卖股票啰
- 天涯社区重启,爷青回?
- 诺基亚在AI时代重新杀回来啦
- 《2049:未来10000天的可能》书中的镜像世界为什么不叫元宇宙
- 今天适合吃披萨
- 开通即被封,别再给Claude送人头了!
- 两根内存条引发的“官司”
- AI·Joe V12更新, 更新GPT-5.5和DeepSeek V4 等
- 中医进校园活动反响热烈
- 猪价低伤农,猪价贵伤民
- Solidity开发指南