rust-web3
rust-web3 copied to clipboard
Getting Events from Transaction Receipts
I would like to use the events
method to get an event from a transaction receipt. I can get the transaction receipt all right, but when I try to get event data, I see the familiar Abi error: Invalid data
result. What is the right way to use this method? I couldn't find any tests or examples.
This is the ABI for the event I want:
{
"name": "FooEvent",
"type": "event",
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"anonymous": false
},
This is the transaction receipt. The event I care about is emitted by the contract at 0x9bc21c339fac72c963e749af847191f452871950
:
Some(
Receipt {
transaction_hash: 0xb0b9cd4716691b6f52714a2b7e04154d60cbeffc3239836a660169312696988d,
transaction_index: 0,
block_hash: Some(
0x2ee8c5507603ef7ce63f9398b7c87433bd407ca1d3e6150f4d05cb3eb5be2663,
),
block_number: Some(
45,
),
cumulative_gas_used: 74275,
gas_used: Some(
74275,
),
contract_address: None,
logs: [
Log {
address: 0xc04c83c52fc7ee1a7a2aa131d4ccc2c2069872a9,
topics: [
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef,
0x000000000000000000000000ba09de4b140597630c56aff1b3a01296ba28982d,
0x0000000000000000000000009bc21c339fac72c963e749af847191f452871950,
],
data: Bytes(
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
69,
99,
145,
130,
68,
244,
0,
0,
],
),
block_hash: Some(
0x2ee8c5507603ef7ce63f9398b7c87433bd407ca1d3e6150f4d05cb3eb5be2663,
),
block_number: Some(
45,
),
transaction_hash: Some(
0xb0b9cd4716691b6f52714a2b7e04154d60cbeffc3239836a660169312696988d,
),
transaction_index: Some(
0,
),
log_index: Some(
0,
),
transaction_log_index: None,
log_type: None,
removed: None,
},
Log {
address: 0xc04c83c52fc7ee1a7a2aa131d4ccc2c2069872a9,
topics: [
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925,
0x000000000000000000000000ba09de4b140597630c56aff1b3a01296ba28982d,
0x0000000000000000000000009bc21c339fac72c963e749af847191f452871950,
],
data: Bytes(
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
],
),
block_hash: Some(
0x2ee8c5507603ef7ce63f9398b7c87433bd407ca1d3e6150f4d05cb3eb5be2663,
),
block_number: Some(
45,
),
transaction_hash: Some(
0xb0b9cd4716691b6f52714a2b7e04154d60cbeffc3239836a660169312696988d,
),
transaction_index: Some(
0,
),
log_index: Some(
1,
),
transaction_log_index: None,
log_type: None,
removed: None,
},
Log {
address: 0x9bc21c339fac72c963e749af847191f452871950,
topics: [
0xf62badb063ea4b26543119fa0f194f8c19665e8c9d635362e24e7681d6cfb6af,
0x000000000000000000000000021c09fbf76579b49c2cd0980d8efe527145652f,
0x000000000000000000000000ba09de4b140597630c56aff1b3a01296ba28982d,
],
data: Bytes(
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
69,
99,
145,
130,
68,
244,
0,
0,
],
),
block_hash: Some(
0x2ee8c5507603ef7ce63f9398b7c87433bd407ca1d3e6150f4d05cb3eb5be2663,
),
block_number: Some(
45,
),
transaction_hash: Some(
0xb0b9cd4716691b6f52714a2b7e04154d60cbeffc3239836a660169312696988d,
),
transaction_index: Some(
0,
),
log_index: Some(
2,
),
transaction_log_index: None,
log_type: None,
removed: None,
},
],
status: Some(
1,
),
root: None,
logs_bloom: 0x00000000000000000100000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000200200000000000000000000000008014000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000010000000200000000000000000000004000000100000000000000000000000000000000000120002000000000200000000000000000000000000020000000000000000000000000002000000000000000000000000000000020000000000000000000000210010000000000000000000000000080000000000000000000000000000100000,
},
)
This is the code:
// -snip-
let txn = contract
.call("foo", (args.amount,), from, Options::default())
.await?;
let receipt = web3.eth().transaction_receipt(txn).await?;
let logs: Vec<Log> = receipt
.unwrap()
.logs
.into_iter()
.filter(|x| x.address == args.address)
.collect::<Vec<_>>();
let log = logs.first().unwrap();
let events: Vec<(Address, Address, U256)> = contract
.events("FooEvent", log.topics[0], log.topics[1], log.topics[2])
.await?;
// -snip-
I was able to get it working by borrowing from the implementation of web3::contract::Contract::events
.
I'm not sure why I wasn't able to use that method directly. Could there be a type mismatch that only shows at runtime?
Here my solution:
// -snip-
let txn = contract
.call("foo", (args.amount,), from, Options::default())
.await?;
let receipt = web3.eth().transaction_receipt(txn).await?;
let logs = receipt
.unwrap()
.logs
.into_iter()
.filter(|x| x.address == args.address)
.collect::<Vec<_>>();
let event: (Address, Address, U256) = Detokenize::from_tokens(
contract
.abi()
.event("FooEvent")
.unwrap()
.parse_log(ethabi::RawLog {
topics: logs.first().unwrap().topics.clone(),
data: logs.first().unwrap().data.0.clone(),
})?
.params
.into_iter()
.map(|x| x.value)
.collect::<Vec<_>>(),
)
.unwrap();
// -snip-
When will it be settled