diff --git a/components/chainhook-cli/src/cli/mod.rs b/components/chainhook-cli/src/cli/mod.rs index c03199fcf..20f5b2363 100644 --- a/components/chainhook-cli/src/cli/mod.rs +++ b/components/chainhook-cli/src/cli/mod.rs @@ -340,8 +340,8 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> { end_block: Some(50000), blocks: None, predicate: StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate { - contract_identifier: "ST1SVA0SST0EDT4MFYGWGP6GNSXMMQJDVP1G8QTTC.arkadiko-freddie-v1-1".into(), - contains: "vault".into(), + contract_identifier: Some("ST1SVA0SST0EDT4MFYGWGP6GNSXMMQJDVP1G8QTTC.arkadiko-freddie-v1-1".into()), + contains: Some("vault".into()), }), expire_after_occurrence: None, capture_all_events: None, @@ -356,8 +356,8 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> { end_block: Some(50000), blocks: None, predicate: StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate { - contract_identifier: "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-freddie-v1-1".into(), - contains: "vault".into(), + contract_identifier: Some("SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-freddie-v1-1".into()), + contains: Some("vault".into()), }), expire_after_occurrence: None, capture_all_events: None, diff --git a/components/chainhook-cli/src/service/tests/mod.rs b/components/chainhook-cli/src/service/tests/mod.rs index 1df115be3..1847db308 100644 --- a/components/chainhook-cli/src/service/tests/mod.rs +++ b/components/chainhook-cli/src/service/tests/mod.rs @@ -300,7 +300,10 @@ async fn it_handles_stacks_predicates_with_network(network: &str) { #[test_case(json!({"scope":"block_height", "between": [100,102]}); "with scope block_height between match")] #[test_case(json!({"scope":"contract_deployment", "deployer": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM"}); "with scope contract_deployment type deployer")] #[test_case(json!({"scope":"contract_call","contract_identifier": "SP000000000000000000002Q6VF78.pox","method": "stack-stx"}); "with scope contract_call")] -#[test_case(json!({"scope":"print_event","contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.monkey-sip09","contains": "vault"}); "with scope print_event")] +#[test_case(json!({"scope":"print_event","contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.monkey-sip09","contains": "vault"}); "with scope print_event both fields")] +#[test_case(json!({"scope":"print_event","contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.monkey-sip09"}); "with scope print_event just contract_identifier")] +#[test_case(json!({"scope":"print_event","contains": "vault"}); "with scope print_event just contains")] +#[test_case(json!({"scope":"print_event"}); "with scope print_event no fields")] #[test_case(json!({"scope":"ft_event","asset_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.cbtc-token::cbtc","actions": ["burn"]}); "with scope ft_event")] #[test_case(json!({"scope":"nft_event","asset_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.monkey-sip09::monkeys","actions": ["mint", "transfer", "burn"]}); "with scope nft_event")] #[test_case(json!({"scope":"stx_event","actions": ["transfer", "lock"]}); "with scope stx_event")] diff --git a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs index ac9955a32..27556c41f 100644 --- a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs @@ -288,12 +288,12 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( expected_deployer, )) => match &transaction.metadata.kind { StacksTransactionKind::ContractDeployment(actual_deployment) => { - if expected_deployer.eq("*") { - true - } else { + if let Some(expected_deployer) = expected_deployer { actual_deployment .contract_identifier .starts_with(expected_deployer) + } else { + true } } _ => false, @@ -386,10 +386,28 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( for event in transaction.metadata.receipt.events.iter() { match event { StacksTransactionEvent::SmartContractEvent(actual) => { - if actual.contract_identifier == expected_event.contract_identifier { + // if the predicate doesn't specify a contract identifier, check every event's values + // if the predicate doesn't specify a contains, match all values + if let Some(contract_identifier) = &expected_event.contract_identifier { + if &actual.contract_identifier == contract_identifier { + let value = + format!("{}", expect_decoded_clarity_value(&actual.hex_value)); + if let Some(contains) = &expected_event.contains { + if value.contains(contains) { + return true; + } + } else { + return true; + } + } + } else { let value = format!("{}", expect_decoded_clarity_value(&actual.hex_value)); - if value.contains(&expected_event.contains) { + if let Some(contains) = &expected_event.contains { + if value.contains(contains) { + return true; + } + } else { return true; } } diff --git a/components/chainhook-sdk/src/chainhooks/tests/mod.rs b/components/chainhook-sdk/src/chainhooks/tests/mod.rs index dca32d1d0..5b0e87cc5 100644 --- a/components/chainhook-sdk/src/chainhooks/tests/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/tests/mod.rs @@ -1,8 +1,11 @@ -use chainhook_types::{StacksChainEvent, StacksChainUpdatedWithBlocksData, StacksBlockUpdate}; +use super::{ + stacks::evaluate_stacks_chainhooks_on_chain_event, + types::{StacksChainhookSpecification, StacksPrintEventBasedPredicate}, +}; +use crate::chainhooks::types::{HookAction, StacksPredicate}; use crate::utils::Context; use chainhook_types::StacksNetwork; -use crate::chainhooks::types::{StacksPredicate, HookAction}; -use super::{stacks::evaluate_stacks_chainhooks_on_chain_event, types::{StacksChainhookSpecification, StacksPrintEventBasedPredicate}}; +use chainhook_types::{StacksBlockUpdate, StacksChainEvent, StacksChainUpdatedWithBlocksData}; pub mod fixtures; @@ -15,7 +18,7 @@ fn test_stacks_predicate_print_event() { parent_microblocks_to_apply: vec![], parent_microblocks_to_rollback: vec![], }], - confirmed_blocks: vec![] + confirmed_blocks: vec![], }); // Prepare predicate @@ -32,14 +35,17 @@ fn test_stacks_predicate_print_event() { capture_all_events: None, decode_clarity_values: None, predicate: StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate { - contract_identifier: "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data".to_string(), - contains: "set-loan".to_string(), + contract_identifier: Some( + "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data".to_string(), + ), + contains: Some("set-loan".to_string()), }), action: HookAction::Noop, enabled: true, }; let predicates = vec![&print_predicate]; - let (triggered, _blocks) = evaluate_stacks_chainhooks_on_chain_event(&event, predicates, &Context::empty()); + let (triggered, _blocks) = + evaluate_stacks_chainhooks_on_chain_event(&event, predicates, &Context::empty()); assert_eq!(triggered.len(), 1); -} \ No newline at end of file +} diff --git a/components/chainhook-sdk/src/chainhooks/types.rs b/components/chainhook-sdk/src/chainhooks/types.rs index 39c06e000..a7fda4b1a 100644 --- a/components/chainhook-sdk/src/chainhooks/types.rs +++ b/components/chainhook-sdk/src/chainhooks/types.rs @@ -762,7 +762,7 @@ pub struct StacksContractCallBasedPredicate { #[serde(rename_all = "snake_case")] // #[serde(tag = "type", content = "rule")] pub enum StacksContractDeploymentPredicate { - Deployer(String), + Deployer(Option), ImplementSip09, ImplementSip10, } @@ -770,8 +770,10 @@ pub enum StacksContractDeploymentPredicate { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct StacksPrintEventBasedPredicate { - pub contract_identifier: String, - pub contains: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub contract_identifier: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub contains: Option, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] diff --git a/docs/chainhook-openapi.json b/docs/chainhook-openapi.json index d66fff1b0..62f0960d6 100644 --- a/docs/chainhook-openapi.json +++ b/docs/chainhook-openapi.json @@ -2,7 +2,7 @@ "openapi": "3.0.0", "info": { "title": "chainhook", - "version": "0.16.0" + "version": "0.17.0" }, "paths": { "/ping": { @@ -993,8 +993,6 @@ { "type": "object", "required": [ - "contains", - "contract_identifier", "scope" ], "properties": { @@ -1005,10 +1003,12 @@ ] }, "contract_identifier": { - "type": "string" + "type": "string", + "nullable": true }, "contains": { - "type": "string" + "type": "string", + "nullable": true } } },