diff --git a/chain/ethereum/src/data_source.rs b/chain/ethereum/src/data_source.rs index 2e38beffee7..c0253d2e60e 100644 --- a/chain/ethereum/src/data_source.rs +++ b/chain/ethereum/src/data_source.rs @@ -1676,6 +1676,7 @@ impl CallDecl { fn address(&self, log: &Log, params: &[LogParam]) -> Result { let address = match &self.expr.address { CallArg::Address => log.address, + CallArg::HexAddress(address) => *address, CallArg::Param(name) => { let value = params .iter() @@ -1697,6 +1698,7 @@ impl CallDecl { .iter() .map(|arg| match arg { CallArg::Address => Ok(Token::Address(log.address)), + CallArg::HexAddress(address) => Ok(Token::Address(*address)), CallArg::Param(name) => { let value = params .iter() @@ -1795,32 +1797,31 @@ impl FromStr for CallExpr { #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub enum CallArg { + HexAddress(Address), Address, Param(Word), } +lazy_static! { + // Matches a 40-character hexadecimal string prefixed with '0x', typical for Ethereum addresses + static ref ADDR_RE: Regex = Regex::new(r"^0x[0-9a-fA-F]{40}$").unwrap(); +} + impl FromStr for CallArg { type Err = anyhow::Error; fn from_str(s: &str) -> Result { - fn invalid(s: &str) -> Result { - Err(anyhow!("invalid call argument `{}`", s)) + if ADDR_RE.is_match(s) { + if let Ok(parsed_address) = Address::from_str(s) { + return Ok(CallArg::HexAddress(parsed_address)); + } } - let mut parts = s.split("."); - match parts.next() { - Some("event") => { /* ok */ } - Some(_) => return Err(anyhow!("call arguments must start with `event`")), - None => return Err(anyhow!("empty call argument")), - } - match parts.next() { - Some("address") => Ok(CallArg::Address), - Some("params") => match parts.next() { - Some(s) => Ok(CallArg::Param(Word::from(s))), - None => invalid(s), - }, - Some(s) => invalid(s), - None => invalid(s), + let mut parts = s.split('.'); + match (parts.next(), parts.next(), parts.next()) { + (Some("event"), Some("address"), None) => Ok(CallArg::Address), + (Some("event"), Some("params"), Some(param)) => Ok(CallArg::Param(Word::from(param))), + _ => Err(anyhow!("invalid call argument `{}`", s)), } } } @@ -1854,4 +1855,14 @@ fn test_call_expr() { assert_eq!(expr.address, CallArg::Address); assert_eq!(expr.func, "growth"); assert_eq!(expr.args, vec![]); + + let expr: CallExpr = "Pool[0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF].growth(0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF)" + .parse() + .unwrap(); + let call_arg = + CallArg::HexAddress(H160::from_str("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF").unwrap()); + assert_eq!(expr.abi, "Pool"); + assert_eq!(expr.address, call_arg); + assert_eq!(expr.func, "growth"); + assert_eq!(expr.args, vec![call_arg]); } diff --git a/store/test-store/tests/chain/ethereum/manifest.rs b/store/test-store/tests/chain/ethereum/manifest.rs index 9f4bd388674..9089ec4f572 100644 --- a/store/test-store/tests/chain/ethereum/manifest.rs +++ b/store/test-store/tests/chain/ethereum/manifest.rs @@ -1409,6 +1409,8 @@ dataSources: calls: fake1: Factory[event.address].get(event.params.address) fake2: Factory[event.params.address].get(event.params.address) + fake3: Factory[0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF].get(event.address) + fake4: Factory[0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF].get(0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF) "; test_store::run_test_sequentially(|store| async move { @@ -1440,6 +1442,6 @@ dataSources: // For more detailed tests of parsing CallDecls see the data_soure // module in chain/ethereum let decls = &ds.mapping.event_handlers[0].calls.decls; - assert_eq!(2, decls.len()); + assert_eq!(4, decls.len()); }); }