rust-web3
rust-web3 copied to clipboard
How to parse contract logs
I just wrote some code to subscribe to the etherdelta contract logs. It is working as expected, but the Log struct itself isn't parsed at all.
Log { address: 0x8d12a197cb00d4747a1fe03395095ce2a5cc6819, topics: [0x6effdda786735d5033bfad5f53e5131abcced9e52be6c507b62d639685fbed6d], 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 24, 14, 193, 89, 82, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 117, 13, 37, 84, 22, 72, 59, 236, 26, 49, 202, 112, 80, 198, 218, 196, 38, 59, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 90, 177, 69, 220, 240, 84, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 131, 239, 77, 161, 236, 59, 185, 96, 32, 209, 8, 13, 0, 180, 54, 172, 228, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 1, 35, 205, 118, 244, 38, 95, 93, 126, 76, 243, 4, 210, 140, 57, 94, 205, 22, 27]), block_hash: Some(0xf35d9e95325c8735d5928f894f5cf58a19ddf5b970d7fa6c0a29427dcd91906e), block_number: Some(7458860), transaction_hash: Some(0x95f32ebacd1747a5179c469638f4777d50f81a3c2ae3af72d06a4114094ef279), transaction_index: Some(7), log_index: Some(4), transaction_log_index: None, log_type: None, removed: Some(false) }
Does a Contract have any helpers for parsing log.data? I'm not seeing anything like this in web3's code, but I do see some log parsing code in the ethabi crate. I don't see how to access the abi object on my contract object though since it is not marked public.
I think this is a little different than #26 since that looks like it is about querying the logs and I've already subscribed to them and just need to parse them, but maybe they can be solved the same way.
Currently not. There is a rudimentary support for that on this branch though: https://github.com/tomusdrw/rust-web3/tree/td-fixes
The entire contract support should be re-worked for strong typing, see #120 and #17
I’m new to rust, so there's probably a much more elegant way to do this, but I think the following illustrates the core concepts
use ethabi::{Event, EventParam, ParamType, Log, RawLog};
[...]
let params = vec![EventParam {
name: "thing".to_string(),
kind: ParamType::Address,
indexed: false
}];
let event = Event {
name: "Thing".to_string(),
inputs: params,
anonymous: false
}
let ev_hash = event.signature();
let receipt = web3.eth()
.transaction_receipt(hash)
.wait()
.unwrap().unwrap();
let log = receipt.logs.iter().find(|log| {
log.topics.iter().find(|topic| topic == &&ev_hash).is_some()
});
match log {
Some(l) => {
Some(event.parse_log(RawLog {
topics: vec![ ev_hash ],
data: l.data.clone().0
}).unwrap())
},
None => None
}
// extract log outputs into your type
Thanks justinbretting,For example:
contract EventTest { event get_log(address a,address b,uint256 c);
function getName(uint256 c) public returns (bool) {
emit get_log(msg.sender,msg.sender,c);
return true;
}
}
after call getName(1) get log:
let hash=log.unwrap().transaction_hash.unwrap(); info!("the hash is {:?}",hash);
use ethabi::{Event, EventParam, ParamType, Log, RawLog};
let params = vec![EventParam {
name: "a".to_string(),
kind: ParamType::Address,
indexed: false
},EventParam {
name: "b".to_string(),
kind: ParamType::Address,
indexed: false
},EventParam {
name: "c".to_string(),
kind: ParamType::Uint(256),
indexed: false
}];
let event = Event {
name: "get_log".to_string(),
inputs: params,
anonymous: false
};
let ev_hash = event.signature();
info!("the ev_hash is {:?}",ev_hash);
let web3_format_hash=web3::types::H256::from_slice(&ev_hash.0);
info!("the web3_format_hash is {:?}",web3_format_hash);
let receipt = web3.eth()
.transaction_receipt(hash)
.await?.unwrap();
info!("the receipt is {:?}",receipt);
let log = receipt.logs.iter().find(|log| {
log.topics.iter().find(|topic| topic == &&web3_format_hash).is_some()
});
let res=match log {
Some(l) => {
Some(event.parse_log(RawLog {
topics: vec![ ev_hash ],
data: l.data.clone().0
})?)
},
None => None
};
info!("the res is {:?}",res);
After successful, You should get Res is :
the res is Some(Log { params: [LogParam { name: "a", value: Address(0x1a1afbd92af983276b5e494465b33ddd84c5c1f6) }, LogParam { name: "b", value: Address(0x1a1afbd92af983276b5e494465b33ddd84c5c1f6) }, LogParam { name: "c", value: Uint(1) }] })
Ok,Now,You can get Event!