diff --git a/Cargo.lock b/Cargo.lock index d976dacad..c23a4808b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -407,7 +407,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chainhook" -version = "1.3.0" +version = "1.3.1" dependencies = [ "ansi_term", "atty", @@ -446,7 +446,7 @@ dependencies = [ [[package]] name = "chainhook-sdk" -version = "0.12.1" +version = "0.12.5" dependencies = [ "base58 0.2.0", "base64 0.21.5", @@ -481,7 +481,7 @@ dependencies = [ [[package]] name = "chainhook-types" -version = "1.3.1" +version = "1.3.3" dependencies = [ "hex", "schemars", diff --git a/components/chainhook-cli/Cargo.toml b/components/chainhook-cli/Cargo.toml index ae07fd139..f5ce0c451 100644 --- a/components/chainhook-cli/Cargo.toml +++ b/components/chainhook-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chainhook" -version = "1.3.0" +version = "1.3.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/components/chainhook-cli/src/service/tests/helpers/mock_stacks_node.rs b/components/chainhook-cli/src/service/tests/helpers/mock_stacks_node.rs index e3f46b3d7..ef7c32a88 100644 --- a/components/chainhook-cli/src/service/tests/helpers/mock_stacks_node.rs +++ b/components/chainhook-cli/src/service/tests/helpers/mock_stacks_node.rs @@ -5,7 +5,7 @@ use chainhook_sdk::indexer::stacks::{NewBlock, NewEvent, NewTransaction}; use chainhook_sdk::types::{ FTBurnEventData, FTMintEventData, FTTransferEventData, NFTBurnEventData, NFTMintEventData, NFTTransferEventData, STXBurnEventData, STXLockEventData, STXMintEventData, - STXTransferEventData, SmartContractEventData, StacksTransactionEvent, + STXTransferEventData, SmartContractEventData, StacksTransactionEventPayload, }; use super::{branch_and_height_to_prefixed_hash, height_to_prefixed_hash}; @@ -21,69 +21,73 @@ pub fn create_tmp_working_dir() -> Result<(String, String), String> { .map_err(|e| format!("failed to create temp working dir: {}", e.to_string()))?; Ok((working_dir, tsv_dir)) } -fn create_stacks_new_event(tx_index: u64, index: u32, event: StacksTransactionEvent) -> NewEvent { +fn create_stacks_new_event( + tx_index: u64, + index: u32, + event: StacksTransactionEventPayload, +) -> NewEvent { let mut event_type = String::new(); - let stx_transfer_event = if let StacksTransactionEvent::STXTransferEvent(data) = &event { + let stx_transfer_event = if let StacksTransactionEventPayload::STXTransferEvent(data) = &event { event_type = format!("stx_transfer"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let stx_mint_event = if let StacksTransactionEvent::STXMintEvent(data) = &event { + let stx_mint_event = if let StacksTransactionEventPayload::STXMintEvent(data) = &event { event_type = format!("stx_mint"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let stx_burn_event = if let StacksTransactionEvent::STXBurnEvent(data) = &event { + let stx_burn_event = if let StacksTransactionEventPayload::STXBurnEvent(data) = &event { event_type = format!("stx_burn"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let stx_lock_event = if let StacksTransactionEvent::STXLockEvent(data) = &event { + let stx_lock_event = if let StacksTransactionEventPayload::STXLockEvent(data) = &event { event_type = format!("stx_lock"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let nft_transfer_event = if let StacksTransactionEvent::NFTTransferEvent(data) = &event { + let nft_transfer_event = if let StacksTransactionEventPayload::NFTTransferEvent(data) = &event { event_type = format!("nft_transfer"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let nft_mint_event = if let StacksTransactionEvent::NFTMintEvent(data) = &event { + let nft_mint_event = if let StacksTransactionEventPayload::NFTMintEvent(data) = &event { event_type = format!("nft_mint"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let nft_burn_event = if let StacksTransactionEvent::NFTBurnEvent(data) = &event { + let nft_burn_event = if let StacksTransactionEventPayload::NFTBurnEvent(data) = &event { event_type = format!("nft_burn"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let ft_transfer_event = if let StacksTransactionEvent::FTTransferEvent(data) = &event { + let ft_transfer_event = if let StacksTransactionEventPayload::FTTransferEvent(data) = &event { event_type = format!("ft_transfer"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let ft_mint_event = if let StacksTransactionEvent::FTMintEvent(data) = &event { + let ft_mint_event = if let StacksTransactionEventPayload::FTMintEvent(data) = &event { event_type = format!("ft_mint"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let ft_burn_event = if let StacksTransactionEvent::FTBurnEvent(data) = &event { + let ft_burn_event = if let StacksTransactionEventPayload::FTBurnEvent(data) = &event { event_type = format!("ft_burn"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let contract_event = if let StacksTransactionEvent::SmartContractEvent(data) = &event { + let contract_event = if let StacksTransactionEventPayload::SmartContractEvent(data) = &event { event_type = format!("smart_contract_print_event"); Some(serde_json::to_value(data).unwrap()) } else { @@ -136,7 +140,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::STXTransferEvent(STXTransferEventData { + StacksTransactionEventPayload::STXTransferEvent(STXTransferEventData { sender: format!(""), recipient: format!(""), amount: format!("1"), @@ -145,7 +149,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::STXMintEvent(STXMintEventData { + StacksTransactionEventPayload::STXMintEvent(STXMintEventData { recipient: format!(""), amount: format!("1"), }), @@ -153,7 +157,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::STXBurnEvent(STXBurnEventData { + StacksTransactionEventPayload::STXBurnEvent(STXBurnEventData { sender: format!(""), amount: format!("1"), }), @@ -161,7 +165,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::STXLockEvent(STXLockEventData { + StacksTransactionEventPayload::STXLockEvent(STXLockEventData { locked_amount: format!("1"), unlock_height: format!(""), locked_address: format!(""), @@ -170,7 +174,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::NFTTransferEvent(NFTTransferEventData { + StacksTransactionEventPayload::NFTTransferEvent(NFTTransferEventData { asset_class_identifier: format!(""), hex_asset_identifier: format!(""), sender: format!(""), @@ -180,7 +184,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::NFTMintEvent(NFTMintEventData { + StacksTransactionEventPayload::NFTMintEvent(NFTMintEventData { asset_class_identifier: format!(""), hex_asset_identifier: format!(""), recipient: format!(""), @@ -189,7 +193,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::NFTBurnEvent(NFTBurnEventData { + StacksTransactionEventPayload::NFTBurnEvent(NFTBurnEventData { asset_class_identifier: format!(""), hex_asset_identifier: format!(""), sender: format!(""), @@ -198,7 +202,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::FTTransferEvent(FTTransferEventData { + StacksTransactionEventPayload::FTTransferEvent(FTTransferEventData { asset_class_identifier: format!(""), sender: format!(""), recipient: format!(""), @@ -208,7 +212,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::FTMintEvent(FTMintEventData { + StacksTransactionEventPayload::FTMintEvent(FTMintEventData { asset_class_identifier: format!(""), recipient: format!(""), amount: format!("1"), @@ -217,7 +221,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::FTBurnEvent(FTBurnEventData { + StacksTransactionEventPayload::FTBurnEvent(FTBurnEventData { asset_class_identifier: format!(""), sender: format!(""), amount: format!("1"), @@ -226,7 +230,7 @@ pub fn create_stacks_new_block(height: u64, burn_block_height: u64) -> NewBlock events.push(create_stacks_new_event( 0, events.len() as u32, - StacksTransactionEvent::SmartContractEvent(SmartContractEventData { + StacksTransactionEventPayload::SmartContractEvent(SmartContractEventData { contract_identifier: format!(""), topic: format!("print"), hex_value: format!(""), diff --git a/components/chainhook-sdk/Cargo.toml b/components/chainhook-sdk/Cargo.toml index 8b0d0beb1..d85a8dcd5 100644 --- a/components/chainhook-sdk/Cargo.toml +++ b/components/chainhook-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chainhook-sdk" -version = "0.12.1" +version = "0.12.5" description = "Stateless Transaction Indexing Engine for Stacks and Bitcoin" license = "GPL-3.0" edition = "2021" @@ -16,7 +16,7 @@ stacks-rpc-client = "2" hiro-system-kit = { version = "0.3.1", optional = true } # stacks-rpc-client = { version = "1", path = "../../../clarinet/components/stacks-rpc-client" } # hiro-system-kit = { version = "0.1.0", path = "../../../clarinet/components/hiro-system-kit" } -chainhook-types = { version = "1.3.0", path = "../chainhook-types-rs" } +chainhook-types = { version = "1.3.3", path = "../chainhook-types-rs" } rocket = { version = "=0.5.0-rc.3", features = ["json"] } bitcoincore-rpc = "0.18.0" bitcoincore-rpc-json = "0.18.0" diff --git a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs index 77902d560..21dfbb048 100644 --- a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs @@ -6,7 +6,7 @@ use super::types::{ }; use chainhook_types::{ BlockIdentifier, StacksChainEvent, StacksTransactionData, StacksTransactionEvent, - StacksTransactionKind, TransactionIdentifier, + StacksTransactionEventPayload, StacksTransactionKind, TransactionIdentifier, }; use hiro_system_kit::slog; use regex::Regex; @@ -376,8 +376,13 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( let expecting_burn = expected_event.actions.contains(&"burn".to_string()); for event in transaction.metadata.receipt.events.iter() { - match (event, expecting_mint, expecting_transfer, expecting_burn) { - (StacksTransactionEvent::FTMintEvent(ft_event), true, _, _) => { + match ( + &event.event_payload, + expecting_mint, + expecting_transfer, + expecting_burn, + ) { + (StacksTransactionEventPayload::FTMintEvent(ft_event), true, _, _) => { if ft_event .asset_class_identifier .eq(&expected_event.asset_identifier) @@ -385,7 +390,7 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( return true; } } - (StacksTransactionEvent::FTTransferEvent(ft_event), _, true, _) => { + (StacksTransactionEventPayload::FTTransferEvent(ft_event), _, true, _) => { if ft_event .asset_class_identifier .eq(&expected_event.asset_identifier) @@ -393,7 +398,7 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( return true; } } - (StacksTransactionEvent::FTBurnEvent(ft_event), _, _, true) => { + (StacksTransactionEventPayload::FTBurnEvent(ft_event), _, _, true) => { if ft_event .asset_class_identifier .eq(&expected_event.asset_identifier) @@ -412,8 +417,13 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( let expecting_burn = expected_event.actions.contains(&"burn".to_string()); for event in transaction.metadata.receipt.events.iter() { - match (event, expecting_mint, expecting_transfer, expecting_burn) { - (StacksTransactionEvent::NFTMintEvent(nft_event), true, _, _) => { + match ( + &event.event_payload, + expecting_mint, + expecting_transfer, + expecting_burn, + ) { + (StacksTransactionEventPayload::NFTMintEvent(nft_event), true, _, _) => { if nft_event .asset_class_identifier .eq(&expected_event.asset_identifier) @@ -421,7 +431,7 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( return true; } } - (StacksTransactionEvent::NFTTransferEvent(nft_event), _, true, _) => { + (StacksTransactionEventPayload::NFTTransferEvent(nft_event), _, true, _) => { if nft_event .asset_class_identifier .eq(&expected_event.asset_identifier) @@ -429,7 +439,7 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( return true; } } - (StacksTransactionEvent::NFTBurnEvent(nft_event), _, _, true) => { + (StacksTransactionEventPayload::NFTBurnEvent(nft_event), _, _, true) => { if nft_event .asset_class_identifier .eq(&expected_event.asset_identifier) @@ -450,16 +460,18 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( for event in transaction.metadata.receipt.events.iter() { match ( - event, + &event.event_payload, expecting_mint, expecting_transfer, expecting_lock, expecting_burn, ) { - (StacksTransactionEvent::STXMintEvent(_), true, _, _, _) => return true, - (StacksTransactionEvent::STXTransferEvent(_), _, true, _, _) => return true, - (StacksTransactionEvent::STXLockEvent(_), _, _, true, _) => return true, - (StacksTransactionEvent::STXBurnEvent(_), _, _, _, true) => return true, + (StacksTransactionEventPayload::STXMintEvent(_), true, _, _, _) => return true, + (StacksTransactionEventPayload::STXTransferEvent(_), _, true, _, _) => { + return true + } + (StacksTransactionEventPayload::STXLockEvent(_), _, _, true, _) => return true, + (StacksTransactionEventPayload::STXBurnEvent(_), _, _, _, true) => return true, _ => continue, } } @@ -467,8 +479,8 @@ pub fn evaluate_stacks_predicate_on_transaction<'a>( } StacksPredicate::PrintEvent(expected_event) => { for event in transaction.metadata.receipt.events.iter() { - match event { - StacksTransactionEvent::SmartContractEvent(actual) => { + match &event.event_payload { + StacksTransactionEventPayload::SmartContractEvent(actual) => { if actual.topic == "print" { match expected_event { StacksPrintEventBasedPredicate::Contains { @@ -592,32 +604,36 @@ pub fn serialized_event_with_decoded_clarity_value( event: &StacksTransactionEvent, ctx: &Context, ) -> serde_json::Value { - match event { - StacksTransactionEvent::STXTransferEvent(payload) => { + match &event.event_payload { + StacksTransactionEventPayload::STXTransferEvent(payload) => { json!({ "type": "STXTransferEvent", - "data": payload + "data": payload, + "position": event.position }) } - StacksTransactionEvent::STXMintEvent(payload) => { + StacksTransactionEventPayload::STXMintEvent(payload) => { json!({ "type": "STXMintEvent", - "data": payload + "data": payload, + "position": event.position }) } - StacksTransactionEvent::STXLockEvent(payload) => { + StacksTransactionEventPayload::STXLockEvent(payload) => { json!({ "type": "STXLockEvent", - "data": payload + "data": payload, + "position": event.position }) } - StacksTransactionEvent::STXBurnEvent(payload) => { + StacksTransactionEventPayload::STXBurnEvent(payload) => { json!({ "type": "STXBurnEvent", - "data": payload + "data": payload, + "position": event.position }) } - StacksTransactionEvent::NFTTransferEvent(payload) => { + StacksTransactionEventPayload::NFTTransferEvent(payload) => { json!({ "type": "NFTTransferEvent", "data": { @@ -625,58 +641,65 @@ pub fn serialized_event_with_decoded_clarity_value( "asset_identifier": serialized_decoded_clarity_value(&payload.hex_asset_identifier, ctx), "sender": payload.sender, "recipient": payload.recipient, - } + }, + "position": event.position }) } - StacksTransactionEvent::NFTMintEvent(payload) => { + StacksTransactionEventPayload::NFTMintEvent(payload) => { json!({ "type": "NFTMintEvent", "data": { "asset_class_identifier": payload.asset_class_identifier, "asset_identifier": serialized_decoded_clarity_value(&payload.hex_asset_identifier, ctx), "recipient": payload.recipient, - } + }, + "position": event.position }) } - StacksTransactionEvent::NFTBurnEvent(payload) => { + StacksTransactionEventPayload::NFTBurnEvent(payload) => { json!({ "type": "NFTBurnEvent", "data": { "asset_class_identifier": payload.asset_class_identifier, "asset_identifier": serialized_decoded_clarity_value(&payload.hex_asset_identifier, ctx), "sender": payload.sender, - } + }, + "position": event.position }) } - StacksTransactionEvent::FTTransferEvent(payload) => { + StacksTransactionEventPayload::FTTransferEvent(payload) => { json!({ "type": "FTTransferEvent", - "data": payload + "data": payload, + "position": event.position }) } - StacksTransactionEvent::FTMintEvent(payload) => { + StacksTransactionEventPayload::FTMintEvent(payload) => { json!({ "type": "FTMintEvent", - "data": payload + "data": payload, + "position": event.position }) } - StacksTransactionEvent::FTBurnEvent(payload) => { + StacksTransactionEventPayload::FTBurnEvent(payload) => { json!({ "type": "FTBurnEvent", - "data": payload + "data": payload, + "position": event.position }) } - StacksTransactionEvent::DataVarSetEvent(payload) => { + StacksTransactionEventPayload::DataVarSetEvent(payload) => { json!({ "type": "DataVarSetEvent", "data": { "contract_identifier": payload.contract_identifier, "var": payload.var, "new_value": serialized_decoded_clarity_value(&payload.hex_new_value, ctx), - } + }, + "position": event.position }) } - StacksTransactionEvent::DataMapInsertEvent(payload) => { + StacksTransactionEventPayload::DataMapInsertEvent(payload) => { json!({ "type": "DataMapInsertEvent", "data": { @@ -684,10 +707,11 @@ pub fn serialized_event_with_decoded_clarity_value( "map": payload.map, "inserted_key": serialized_decoded_clarity_value(&payload.hex_inserted_key, ctx), "inserted_value": serialized_decoded_clarity_value(&payload.hex_inserted_value, ctx), - } + }, + "position": event.position }) } - StacksTransactionEvent::DataMapUpdateEvent(payload) => { + StacksTransactionEventPayload::DataMapUpdateEvent(payload) => { json!({ "type": "DataMapUpdateEvent", "data": { @@ -695,27 +719,30 @@ pub fn serialized_event_with_decoded_clarity_value( "map": payload.map, "key": serialized_decoded_clarity_value(&payload.hex_key, ctx), "new_value": serialized_decoded_clarity_value(&payload.hex_new_value, ctx), - } + }, + "position": event.position }) } - StacksTransactionEvent::DataMapDeleteEvent(payload) => { + StacksTransactionEventPayload::DataMapDeleteEvent(payload) => { json!({ "type": "DataMapDeleteEvent", "data": { "contract_identifier": payload.contract_identifier, "map": payload.map, "deleted_key": serialized_decoded_clarity_value(&payload.hex_deleted_key, ctx), - } + }, + "position": event.position }) } - StacksTransactionEvent::SmartContractEvent(payload) => { + StacksTransactionEventPayload::SmartContractEvent(payload) => { json!({ "type": "SmartContractEvent", "data": { "contract_identifier": payload.contract_identifier, "topic": payload.topic, "value": serialized_decoded_clarity_value(&payload.hex_value, ctx), - } + }, + "position": event.position }) } } diff --git a/components/chainhook-sdk/src/chainhooks/tests/fixtures/mod.rs b/components/chainhook-sdk/src/chainhooks/tests/fixtures/mod.rs index cf5295d73..b931db7d8 100644 --- a/components/chainhook-sdk/src/chainhooks/tests/fixtures/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/tests/fixtures/mod.rs @@ -1,9 +1,10 @@ -use chainhook_types::StacksBlockData; use chainhook_types::{ FTBurnEventData, FTMintEventData, FTTransferEventData, NFTBurnEventData, NFTMintEventData, NFTTransferEventData, STXBurnEventData, STXLockEventData, STXMintEventData, - STXTransferEventData, SmartContractEventData, StacksTransactionData, StacksTransactionEvent, + STXTransferEventData, SmartContractEventData, StacksTransactionData, + StacksTransactionEventPayload, }; +use chainhook_types::{StacksBlockData, StacksTransactionEvent}; use std::collections::HashMap; lazy_static! { @@ -71,71 +72,71 @@ pub fn get_expected_occurrence() -> String { std::include_str!("stacks/testnet/occurrence.json").to_owned() } -pub fn get_all_event_types() -> Vec { +pub fn get_all_event_payload_types() -> Vec { vec![ - get_test_event_by_type("stx_transfer"), - get_test_event_by_type("stx_mint"), - get_test_event_by_type("stx_lock"), - get_test_event_by_type("stx_burn"), - get_test_event_by_type("nft_transfer"), - get_test_event_by_type("nft_mint"), - get_test_event_by_type("nft_burn"), - get_test_event_by_type("ft_transfer"), - get_test_event_by_type("ft_mint"), - get_test_event_by_type("ft_burn"), - get_test_event_by_type("smart_contract_print_event"), - get_test_event_by_type("smart_contract_print_event_empty"), - get_test_event_by_type("smart_contract_not_print_event"), + get_test_event_payload_by_type("stx_transfer"), + get_test_event_payload_by_type("stx_mint"), + get_test_event_payload_by_type("stx_lock"), + get_test_event_payload_by_type("stx_burn"), + get_test_event_payload_by_type("nft_transfer"), + get_test_event_payload_by_type("nft_mint"), + get_test_event_payload_by_type("nft_burn"), + get_test_event_payload_by_type("ft_transfer"), + get_test_event_payload_by_type("ft_mint"), + get_test_event_payload_by_type("ft_burn"), + get_test_event_payload_by_type("smart_contract_print_event"), + get_test_event_payload_by_type("smart_contract_print_event_empty"), + get_test_event_payload_by_type("smart_contract_not_print_event"), ] } -pub fn get_test_event_by_type(event_type: &str) -> StacksTransactionEvent { +pub fn get_test_event_payload_by_type(event_type: &str) -> StacksTransactionEventPayload { match event_type { - "stx_transfer" => StacksTransactionEvent::STXTransferEvent(STXTransferEventData { + "stx_transfer" => StacksTransactionEventPayload::STXTransferEvent(STXTransferEventData { sender: "".to_string(), recipient: "".to_string(), amount: "".to_string(), }), - "stx_mint" => StacksTransactionEvent::STXMintEvent(STXMintEventData { + "stx_mint" => StacksTransactionEventPayload::STXMintEvent(STXMintEventData { recipient: "".to_string(), amount: "".to_string(), }), - "stx_lock" => StacksTransactionEvent::STXLockEvent(STXLockEventData { + "stx_lock" => StacksTransactionEventPayload::STXLockEvent(STXLockEventData { locked_amount: "".to_string(), unlock_height: "".to_string(), locked_address: "".to_string(), }), - "stx_burn" => StacksTransactionEvent::STXBurnEvent(STXBurnEventData { + "stx_burn" => StacksTransactionEventPayload::STXBurnEvent(STXBurnEventData { sender: "".to_string(), amount: "".to_string(), }), - "nft_transfer" => StacksTransactionEvent::NFTTransferEvent(NFTTransferEventData { + "nft_transfer" => StacksTransactionEventPayload::NFTTransferEvent(NFTTransferEventData { sender: "".to_string(), asset_class_identifier: "asset-id".to_string(), hex_asset_identifier: "asset-id".to_string(), recipient: "".to_string(), }), - "nft_mint" => StacksTransactionEvent::NFTMintEvent(NFTMintEventData { + "nft_mint" => StacksTransactionEventPayload::NFTMintEvent(NFTMintEventData { asset_class_identifier: "asset-id".to_string(), hex_asset_identifier: "asset-id".to_string(), recipient: "".to_string(), }), - "nft_burn" => StacksTransactionEvent::NFTBurnEvent(NFTBurnEventData { + "nft_burn" => StacksTransactionEventPayload::NFTBurnEvent(NFTBurnEventData { asset_class_identifier: "asset-id".to_string(), hex_asset_identifier: "asset-id".to_string(), sender: "".to_string(), }), - "ft_transfer" => StacksTransactionEvent::FTTransferEvent(FTTransferEventData { + "ft_transfer" => StacksTransactionEventPayload::FTTransferEvent(FTTransferEventData { sender: "".to_string(), asset_class_identifier: "asset-id".to_string(), amount: "".to_string(), recipient: "".to_string(), }), - "ft_mint" => StacksTransactionEvent::FTMintEvent(FTMintEventData { + "ft_mint" => StacksTransactionEventPayload::FTMintEvent(FTMintEventData { asset_class_identifier: "asset-id".to_string(), recipient: "".to_string(), amount: "".to_string(), }), - "ft_burn" => StacksTransactionEvent::FTBurnEvent(FTBurnEventData { + "ft_burn" => StacksTransactionEventPayload::FTBurnEvent(FTBurnEventData { asset_class_identifier: "asset-id".to_string(), sender: "".to_string(), amount: "".to_string(), @@ -145,7 +146,7 @@ pub fn get_test_event_by_type(event_type: &str) -> StacksTransactionEvent { "data_map_update" => todo!(), "data_map_delete" => todo!(), "smart_contract_print_event" => { - StacksTransactionEvent::SmartContractEvent(SmartContractEventData { + StacksTransactionEventPayload::SmartContractEvent(SmartContractEventData { topic: "print".to_string(), contract_identifier: "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data" .to_string(), @@ -153,14 +154,14 @@ pub fn get_test_event_by_type(event_type: &str) -> StacksTransactionEvent { }) } "smart_contract_print_event_empty" => { - StacksTransactionEvent::SmartContractEvent(SmartContractEventData { + StacksTransactionEventPayload::SmartContractEvent(SmartContractEventData { topic: "print".to_string(), contract_identifier: "some-id".to_string(), hex_value: EMPTY_EVENT_HEX.to_string(), }) } "smart_contract_not_print_event" => { - StacksTransactionEvent::SmartContractEvent(SmartContractEventData { + StacksTransactionEventPayload::SmartContractEvent(SmartContractEventData { topic: "not-print".to_string(), contract_identifier: "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data" .to_string(), diff --git a/components/chainhook-sdk/src/chainhooks/tests/fixtures/stacks/testnet/occurrence.json b/components/chainhook-sdk/src/chainhooks/tests/fixtures/stacks/testnet/occurrence.json index 76b8b30d2..9dc863fc9 100644 --- a/components/chainhook-sdk/src/chainhooks/tests/fixtures/stacks/testnet/occurrence.json +++ b/components/chainhook-sdk/src/chainhooks/tests/fixtures/stacks/testnet/occurrence.json @@ -59,6 +59,9 @@ "recipient": "", "sender": "" }, + "position": { + "index": 0 + }, "type": "STXTransferEvent" } ], @@ -137,6 +140,9 @@ "amount": "", "recipient": "" }, + "position": { + "index": 0 + }, "type": "STXMintEvent" } ], @@ -216,6 +222,9 @@ "locked_amount": "", "unlock_height": "" }, + "position": { + "index": 0 + }, "type": "STXLockEvent" } ], @@ -294,6 +303,9 @@ "amount": "", "sender": "" }, + "position": { + "index": 0 + }, "type": "STXBurnEvent" } ], @@ -374,6 +386,9 @@ "recipient": "", "sender": "" }, + "position": { + "index": 0 + }, "type": "NFTTransferEvent" } ], @@ -453,6 +468,9 @@ "asset_identifier": "asset-id", "recipient": "" }, + "position": { + "index": 0 + }, "type": "NFTMintEvent" } ], @@ -532,6 +550,9 @@ "asset_identifier": "asset-id", "sender": "" }, + "position": { + "index": 0 + }, "type": "NFTBurnEvent" } ], @@ -612,6 +633,9 @@ "recipient": "", "sender": "" }, + "position": { + "index": 0 + }, "type": "FTTransferEvent" } ], @@ -691,6 +715,9 @@ "asset_identifier": "asset-id", "recipient": "" }, + "position": { + "index": 0 + }, "type": "FTMintEvent" } ], @@ -770,6 +797,9 @@ "asset_identifier": "asset-id", "sender": "" }, + "position": { + "index": 0 + }, "type": "FTBurnEvent" } ], @@ -849,6 +879,9 @@ "topic": "print", "value": "abcsome-valueabc" }, + "position": { + "index": 0 + }, "type": "SmartContractEvent" } ], @@ -928,6 +961,9 @@ "topic": "print", "value": "" }, + "position": { + "index": 0 + }, "type": "SmartContractEvent" } ], @@ -1007,6 +1043,9 @@ "topic": "not-print", "value": "abcsome-valueabc" }, + "position": { + "index": 0 + }, "type": "SmartContractEvent" } ], diff --git a/components/chainhook-sdk/src/chainhooks/tests/mod.rs b/components/chainhook-sdk/src/chainhooks/tests/mod.rs index b1486c85a..ecedbed5d 100644 --- a/components/chainhook-sdk/src/chainhooks/tests/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/tests/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use self::fixtures::get_all_event_types; +use self::fixtures::get_all_event_payload_types; use super::{ stacks::{ @@ -17,13 +17,16 @@ use super::{ use crate::{chainhooks::stacks::serialize_stacks_payload_to_json, utils::Context}; use crate::{ chainhooks::{ - tests::fixtures::{get_expected_occurrence, get_test_event_by_type}, + tests::fixtures::{get_expected_occurrence, get_test_event_payload_by_type}, types::{HookAction, StacksPredicate, StacksStxEventBasedPredicate}, }, utils::AbstractStacksBlock, }; -use chainhook_types::{StacksBlockUpdate, StacksChainEvent, StacksChainUpdatedWithBlocksData}; -use chainhook_types::{StacksNetwork, StacksTransactionData, StacksTransactionEvent}; +use chainhook_types::{ + StacksBlockUpdate, StacksChainEvent, StacksChainUpdatedWithBlocksData, StacksNetwork, + StacksTransactionData, StacksTransactionEvent, StacksTransactionEventPayload, + StacksTransactionEventPosition, +}; use serde_json::Value as JsonValue; use test_case::test_case; @@ -31,7 +34,7 @@ pub mod fixtures; // FtEvent predicate tests #[test_case( - vec![vec![get_test_event_by_type("ft_mint")]], + vec![vec![get_test_event_payload_by_type("ft_mint")]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["mint".to_string()] @@ -40,7 +43,7 @@ pub mod fixtures; "FtEvent predicates match mint event" )] #[test_case( - vec![vec![get_test_event_by_type("ft_transfer")]], + vec![vec![get_test_event_payload_by_type("ft_transfer")]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["transfer".to_string()] @@ -49,17 +52,17 @@ pub mod fixtures; "FtEvent predicates match transfer event" )] #[test_case( - vec![vec![StacksTransactionEvent::FTTransferEvent(chainhook_types::FTTransferEventData { + vec![vec![StacksTransactionEventPayload::FTTransferEvent(chainhook_types::FTTransferEventData { sender: "".to_string(), asset_class_identifier: "different-id".to_string(), amount: "".to_string(), recipient: "".to_string(), - }), StacksTransactionEvent::FTTransferEvent(chainhook_types::FTTransferEventData { + }), StacksTransactionEventPayload::FTTransferEvent(chainhook_types::FTTransferEventData { sender: "".to_string(), asset_class_identifier: "asset-id".to_string(), amount: "".to_string(), recipient: "".to_string(), - })]], + })]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["transfer".to_string()] @@ -68,7 +71,7 @@ pub mod fixtures; "FtEvent predicates match transfer event if matching event is not first in transaction" )] #[test_case( - vec![vec![get_test_event_by_type("ft_burn")]], + vec![vec![get_test_event_payload_by_type("ft_burn")]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["burn".to_string()] @@ -77,7 +80,7 @@ pub mod fixtures; "FtEvent predicates match burn event" )] #[test_case( - vec![vec![get_test_event_by_type("ft_mint")]], + vec![vec![get_test_event_payload_by_type("ft_mint")]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "wrong-id".to_string(), actions: vec!["mint".to_string()] @@ -86,7 +89,7 @@ pub mod fixtures; "FtEvent predicates reject no-match asset id for mint event" )] #[test_case( - vec![vec![get_test_event_by_type("ft_transfer")]], + vec![vec![get_test_event_payload_by_type("ft_transfer")]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "wrong-id".to_string(), actions: vec!["transfer".to_string()] @@ -95,7 +98,7 @@ pub mod fixtures; "FtEvent predicates reject no-match asset id for transfer event" )] #[test_case( - vec![vec![get_test_event_by_type("ft_burn")]], + vec![vec![get_test_event_payload_by_type("ft_burn")]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "wrong-id".to_string(), actions: vec!["burn".to_string()] @@ -104,7 +107,7 @@ pub mod fixtures; "FtEvent predicates reject no-match asset id for burn event" )] #[test_case( - vec![vec![get_test_event_by_type("ft_mint")],vec![get_test_event_by_type("ft_transfer")],vec![get_test_event_by_type("ft_burn")]], + vec![vec![get_test_event_payload_by_type("ft_mint")],vec![get_test_event_payload_by_type("ft_transfer")],vec![get_test_event_payload_by_type("ft_burn")]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["mint".to_string(),"transfer".to_string(), "burn".to_string()] @@ -113,7 +116,7 @@ pub mod fixtures; "FtEvent predicates match multiple events" )] #[test_case( - vec![vec![get_test_event_by_type("ft_transfer")],vec![get_test_event_by_type("ft_burn")]], + vec![vec![get_test_event_payload_by_type("ft_transfer")],vec![get_test_event_payload_by_type("ft_burn")]], StacksPredicate::FtEvent(StacksFtEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["mint".to_string()] @@ -123,7 +126,7 @@ pub mod fixtures; )] // NftEvent predicate tests #[test_case( - vec![vec![get_test_event_by_type("nft_mint")]], + vec![vec![get_test_event_payload_by_type("nft_mint")]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["mint".to_string()] @@ -132,7 +135,7 @@ pub mod fixtures; "NftEvent predicates match mint event" )] #[test_case( - vec![vec![get_test_event_by_type("nft_transfer")]], + vec![vec![get_test_event_payload_by_type("nft_transfer")]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["transfer".to_string()] @@ -141,17 +144,17 @@ pub mod fixtures; "NftEvent predicates match transfer event" )] #[test_case( - vec![vec![StacksTransactionEvent::NFTTransferEvent(chainhook_types::NFTTransferEventData { + vec![vec![StacksTransactionEventPayload::NFTTransferEvent(chainhook_types::NFTTransferEventData { sender: "".to_string(), asset_class_identifier: "different-id".to_string(), hex_asset_identifier: "different-id".to_string(), recipient: "".to_string(), - }), StacksTransactionEvent::NFTTransferEvent(chainhook_types::NFTTransferEventData { + }), StacksTransactionEventPayload::NFTTransferEvent(chainhook_types::NFTTransferEventData { sender: "".to_string(), asset_class_identifier: "asset-id".to_string(), hex_asset_identifier: "asset-id".to_string(), recipient: "".to_string(), - })]], + })]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["transfer".to_string()] @@ -160,7 +163,7 @@ pub mod fixtures; "NftEvent predicates match transfer event if matching event is not first in transaction" )] #[test_case( - vec![vec![get_test_event_by_type("nft_burn")]], + vec![vec![get_test_event_payload_by_type("nft_burn")]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["burn".to_string()] @@ -169,7 +172,7 @@ pub mod fixtures; "NftEvent predicates match burn event" )] #[test_case( - vec![vec![get_test_event_by_type("nft_mint")]], + vec![vec![get_test_event_payload_by_type("nft_mint")]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "wrong-id".to_string(), actions: vec!["mint".to_string()] @@ -178,7 +181,7 @@ pub mod fixtures; "NftEvent predicates reject no-match asset id for mint event" )] #[test_case( - vec![vec![get_test_event_by_type("nft_transfer")]], + vec![vec![get_test_event_payload_by_type("nft_transfer")]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "wrong-id".to_string(), actions: vec!["transfer".to_string()] @@ -187,7 +190,7 @@ pub mod fixtures; "NftEvent predicates reject no-match asset id for transfer event" )] #[test_case( - vec![vec![get_test_event_by_type("nft_burn")]], + vec![vec![get_test_event_payload_by_type("nft_burn")]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "wrong-id".to_string(), actions: vec!["burn".to_string()] @@ -196,7 +199,7 @@ pub mod fixtures; "NftEvent predicates reject no-match asset id for burn event" )] #[test_case( - vec![vec![get_test_event_by_type("nft_mint")],vec![get_test_event_by_type("nft_transfer")],vec![get_test_event_by_type("nft_burn")]], + vec![vec![get_test_event_payload_by_type("nft_mint")],vec![get_test_event_payload_by_type("nft_transfer")],vec![get_test_event_payload_by_type("nft_burn")]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["mint".to_string(),"transfer".to_string(), "burn".to_string()] @@ -205,7 +208,7 @@ pub mod fixtures; "NftEvent predicates match multiple events" )] #[test_case( - vec![vec![get_test_event_by_type("nft_transfer")],vec![get_test_event_by_type("nft_burn")]], + vec![vec![get_test_event_payload_by_type("nft_transfer")],vec![get_test_event_payload_by_type("nft_burn")]], StacksPredicate::NftEvent(StacksNftEventBasedPredicate { asset_identifier: "asset-id".to_string(), actions: vec!["mint".to_string()] @@ -215,7 +218,7 @@ pub mod fixtures; )] // StxEvent predicate tests #[test_case( - vec![vec![get_test_event_by_type("stx_mint")]], + vec![vec![get_test_event_payload_by_type("stx_mint")]], StacksPredicate::StxEvent(StacksStxEventBasedPredicate { actions: vec!["mint".to_string()] }), @@ -223,7 +226,7 @@ pub mod fixtures; "StxEvent predicates match mint event" )] #[test_case( - vec![vec![get_test_event_by_type("stx_transfer")]], + vec![vec![get_test_event_payload_by_type("stx_transfer")]], StacksPredicate::StxEvent(StacksStxEventBasedPredicate { actions: vec!["transfer".to_string()] }), @@ -231,7 +234,7 @@ pub mod fixtures; "StxEvent predicates match transfer event" )] #[test_case( - vec![vec![get_test_event_by_type("stx_lock")]], + vec![vec![get_test_event_payload_by_type("stx_lock")]], StacksPredicate::StxEvent(StacksStxEventBasedPredicate { actions: vec!["lock".to_string()] }), @@ -239,7 +242,7 @@ pub mod fixtures; "StxEvent predicates match lock event" )] #[test_case( - vec![vec![get_test_event_by_type("stx_burn")]], + vec![vec![get_test_event_payload_by_type("stx_burn")]], StacksPredicate::StxEvent(StacksStxEventBasedPredicate { actions: vec!["burn".to_string()] }), @@ -247,7 +250,7 @@ pub mod fixtures; "StxEvent predicates match burn event" )] #[test_case( - vec![vec![get_test_event_by_type("stx_mint")],vec![get_test_event_by_type("stx_transfer")],vec![get_test_event_by_type("stx_lock")]], + vec![vec![get_test_event_payload_by_type("stx_mint")],vec![get_test_event_payload_by_type("stx_transfer")],vec![get_test_event_payload_by_type("stx_lock")]], StacksPredicate::StxEvent(StacksStxEventBasedPredicate { actions: vec!["mint".to_string(), "transfer".to_string(), "lock".to_string()] }), @@ -255,7 +258,7 @@ pub mod fixtures; "StxEvent predicates match multiple events" )] #[test_case( - vec![vec![get_test_event_by_type("stx_transfer")],vec![get_test_event_by_type("stx_lock")]], + vec![vec![get_test_event_payload_by_type("stx_transfer")],vec![get_test_event_payload_by_type("stx_lock")]], StacksPredicate::StxEvent(StacksStxEventBasedPredicate { actions: vec!["mint".to_string()] }), @@ -264,7 +267,7 @@ pub mod fixtures; )] // PrintEvent predicate tests #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::Contains { contract_identifier: "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data".to_string(), contains: "some-value".to_string() @@ -273,7 +276,7 @@ pub mod fixtures; "PrintEvent predicate matches contract_identifier and contains" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_not_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_not_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::Contains { contract_identifier: "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data".to_string(), contains: "some-value".to_string(), @@ -282,7 +285,7 @@ pub mod fixtures; "PrintEvent predicate does not check events with topic other than print" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::Contains { contract_identifier: "wront-id".to_string(), contains: "some-value".to_string(), @@ -291,7 +294,7 @@ pub mod fixtures; "PrintEvent predicate rejects non matching contract_identifier" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::Contains { contract_identifier: "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data".to_string(), @@ -301,7 +304,7 @@ pub mod fixtures; "PrintEvent predicate rejects non matching contains value" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::Contains { contract_identifier: "*".to_string(), contains: "some-value".to_string(), @@ -310,7 +313,7 @@ pub mod fixtures; "PrintEvent predicate contract_identifier wildcard checks all print events for match" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::Contains { contract_identifier: "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data".to_string(), contains: "*".to_string(), @@ -319,7 +322,7 @@ pub mod fixtures; "PrintEvent predicate contains wildcard matches all values for matching events" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")], vec![get_test_event_by_type("smart_contract_print_event_empty")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")], vec![get_test_event_payload_by_type("smart_contract_print_event_empty")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::Contains { contract_identifier: "*".to_string(), contains: "*".to_string(), @@ -328,7 +331,7 @@ pub mod fixtures; "PrintEvent predicate contract_identifier wildcard and contains wildcard matches all values on all print events" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::MatchesRegex { contract_identifier: "ST3AXH4EBHD63FCFPTZ8GR29TNTVWDYPGY0KDY5E5.loan-data".to_string(), regex: "(some)|(value)".to_string(), @@ -337,7 +340,7 @@ pub mod fixtures; "PrintEvent predicate matches contract_identifier and regex" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::MatchesRegex { contract_identifier: "*".to_string(), regex: "(some)|(value)".to_string(), @@ -346,7 +349,7 @@ pub mod fixtures; "PrintEvent predicate contract_identifier wildcard checks all print events for match with regex" )] #[test_case( - vec![vec![get_test_event_by_type("smart_contract_print_event")]], + vec![vec![get_test_event_payload_by_type("smart_contract_print_event")]], StacksPredicate::PrintEvent(StacksPrintEventBasedPredicate::MatchesRegex { contract_identifier: "*".to_string(), regex: "[".to_string(), @@ -356,15 +359,27 @@ pub mod fixtures; "PrintEvent predicate does not match invalid regex" )] fn test_stacks_predicates( - blocks_with_events: Vec>, + blocks_with_events: Vec>, predicate: StacksPredicate, expected_applies: u64, ) { // Prepare block let new_blocks = blocks_with_events - .iter() - .map(|events| StacksBlockUpdate { - block: fixtures::build_stacks_testnet_block_from_smart_contract_event_data(events), + .into_iter() + .map(|payloads| StacksBlockUpdate { + block: fixtures::build_stacks_testnet_block_from_smart_contract_event_data( + payloads + .into_iter() + .enumerate() + .map(|(index, payload)| StacksTransactionEvent { + event_payload: payload, + position: StacksTransactionEventPosition { + index: index as u32, + }, + }) + .collect::>() + .as_ref(), + ), parent_microblocks_to_apply: vec![], parent_microblocks_to_rollback: vec![], }) @@ -406,7 +421,7 @@ fn test_stacks_predicates( } #[test_case( - StacksPredicate::ContractDeployment(StacksContractDeploymentPredicate::Deployer("ST13F481SBR0R7Z6NMMH8YV2FJJYXA5JPA0AD3HP9".to_string())), + StacksPredicate::ContractDeployment(StacksContractDeploymentPredicate::Deployer("ST13F481SBR0R7Z6NMMH8YV2FJJYXA5JPA0AD3HP9".to_string())), 1; "Deployer predicate matches by contract deployer" )] @@ -620,12 +635,12 @@ fn verify_optional_addition_of_contract_abi() { "ContractCall predicate does not match for wrong contract identifier" )] #[test_case( - StacksPredicate::Txid(ExactMatchingRule::Equals("0xb92c2ade84a8b85f4c72170680ae42e65438aea4db72ba4b2d6a6960f4141ce8".to_string())), + StacksPredicate::Txid(ExactMatchingRule::Equals("0xb92c2ade84a8b85f4c72170680ae42e65438aea4db72ba4b2d6a6960f4141ce8".to_string())), 1; "Txid predicate matches by a transaction's id" )] #[test_case( - StacksPredicate::Txid(ExactMatchingRule::Equals("wrong-id".to_string())), + StacksPredicate::Txid(ExactMatchingRule::Equals("wrong-id".to_string())), 0; "Txid predicate rejects non matching id" )] @@ -763,15 +778,18 @@ fn test_stacks_hook_action_file_append() { enabled: true, expired_at: None, }; - let events = get_all_event_types(); - let mut apply_blocks = vec![]; - for event in events.iter() { - apply_blocks.push( + let payloads = get_all_event_payload_types(); + let apply_blocks = payloads + .into_iter() + .map(|payload| { fixtures::build_stacks_testnet_block_from_smart_contract_event_data(&vec![ - event.to_owned() - ]), - ); - } + StacksTransactionEvent { + event_payload: payload, + position: StacksTransactionEventPosition { index: 0 }, + }, + ]) + }) + .collect::>(); let apply: Vec<(Vec<&StacksTransactionData>, &dyn AbstractStacksBlock)> = apply_blocks .iter() .map(|b| { diff --git a/components/chainhook-sdk/src/chainhooks/types.rs b/components/chainhook-sdk/src/chainhooks/types.rs index 4e8d51c08..7f6f4158a 100644 --- a/components/chainhook-sdk/src/chainhooks/types.rs +++ b/components/chainhook-sdk/src/chainhooks/types.rs @@ -573,10 +573,6 @@ pub struct PoxConfig { } impl PoxConfig { - pub fn is_consensus_rewarding_participants_at_block_height(&self, block_height: u64) -> bool { - self.get_pos_in_pox_cycle(block_height) < self.reward_phase_len - } - pub fn get_pox_cycle_len(&self) -> u64 { self.prepare_phase_len + self.reward_phase_len } diff --git a/components/chainhook-sdk/src/indexer/bitcoin/mod.rs b/components/chainhook-sdk/src/indexer/bitcoin/mod.rs index db3c73e18..034eda6a8 100644 --- a/components/chainhook-sdk/src/indexer/bitcoin/mod.rs +++ b/components/chainhook-sdk/src/indexer/bitcoin/mod.rs @@ -509,64 +509,83 @@ fn try_parse_stacks_operation( let mut pox_sats_burnt = 0; let mut pox_sats_transferred = vec![]; - // We need to determine wether the transaction was a PoB or a Pox commitment - let mining_output_index = if pox_config - .is_consensus_rewarding_participants_at_block_height(block_height) + let output_1 = outputs + .get(1) + .ok_or(format!("expected output 1 not found")) + .ok()?; + let script_1 = output_1 + .script_pub_key + .script() + .map_err(|_e| format!("expected output 1 corrupted")) + .ok()?; + let address_1 = Address::from_script(&script_1, bitcoin::Network::Bitcoin) + .map_err(|_e| format!("expected output 1 corrupted")) + .ok()?; + + let output_2 = outputs + .get(2) + .ok_or(format!("expected output 2 not found")) + .ok()?; + let script_2 = output_2 + .script_pub_key + .script() + .map_err(|_e| format!("expected output 2 corrupted")) + .ok()?; + let address_2 = Address::from_script(&script_2, bitcoin::Network::Bitcoin) + .map_err(|_e| format!("expected output 2 corrupted")) + .ok()?; + + let output_1_is_burn = address_1.to_string().eq(pox_config.get_burn_address()); + let output_2_is_burn = address_2.to_string().eq(pox_config.get_burn_address()); + + // PoX commitments have the following outputs: + // - 0: OP_RETURN + // - 1: rewarding address (could be a reward address, could be burn address in some rare cases) + // - 2: rewarding address (could be a reward address, could be burn address in some rare cases; always burn address if 1 was burn address) + // - [3-n]: change outputs + // + // PoB commitments have: + // - 0: OP_RETURN + // - 1: Burn address + // - [3-n]: change outputs + // + // So, to determine if PoX vs PoB, we check if output 1 is the burn address + // - If not, we definitely have a PoX block commitment + // - If it is, we need to check if output 2 is the burn address + // - If it is, we have a PoX block commitment + // - If not, we have a PoB block commitment + // + // The only assumption we're making in this logic is that the first change output doesn't + // get sent to the burn address, in which case we'd incorrectly label a PoB block commitment as Pox. + let mining_output_index = if !output_1_is_burn || (output_1_is_burn && output_2_is_burn) { + // We have a PoX Block Commitment // Output 0 is OP_RETURN // Output 1 is rewarding Address 1 - let pox_output_1 = outputs - .get(1) - .ok_or(format!("expected pox output 1 not found")) - .ok()?; - let pox_script_1 = pox_output_1 - .script_pub_key - .script() - .map_err(|_e| format!("expected pox output 1 corrupted")) - .ok()?; - let pox_address_1 = Address::from_script(&pox_script_1, bitcoin::Network::Bitcoin) - .map_err(|_e| format!("expected pox output 1 corrupted")) - .ok()?; - if pox_address_1.to_string().eq(&pox_config.get_burn_address()) { - pox_sats_burnt += pox_output_1.value.to_sat(); + if output_1_is_burn { + pox_sats_burnt += output_1.value.to_sat(); } else { pox_sats_transferred.push(PoxReward { - recipient_address: pox_address_1.to_string(), - amount: pox_output_1.value.to_sat(), + recipient_address: address_1.to_string(), + amount: output_1.value.to_sat(), }); } // Output 2 is rewarding Address 2 - let pox_output_2 = outputs - .get(2) - .ok_or(format!("expected pox output 2 not found")) - .ok()?; - let pox_script_2 = pox_output_2 - .script_pub_key - .script() - .map_err(|_e| format!("expected pox output 2 corrupted")) - .ok()?; - let pox_address_2 = Address::from_script(&pox_script_2, bitcoin::Network::Bitcoin) - .map_err(|_e| format!("expected pox output 2 corrupted")) - .ok()?; - if pox_address_2.to_string().eq(&pox_config.get_burn_address()) { - pox_sats_burnt += pox_output_2.value.to_sat(); + if output_2_is_burn { + pox_sats_burnt += output_2.value.to_sat(); } else { pox_sats_transferred.push(PoxReward { - recipient_address: pox_address_2.to_string(), - amount: pox_output_2.value.to_sat(), + recipient_address: address_2.to_string(), + amount: output_2.value.to_sat(), }); } // Output 3 is used for miner chained commitments 3 } else { + // We have a PoB Block Commitment // Output 0 is OP_RETURN - // Output 1 should be a Burn Address - let burn_output = outputs - .get(1) - .ok_or(format!("expected burn address not found")) - .ok()?; - // Todo: Ensure that we're looking at a burn address - pox_sats_burnt += burn_output.value.to_sat(); + // Output 1 is be a Burn Address + pox_sats_burnt += output_1.value.to_sat(); // Output 2 is used for miner chained commitments 2 }; diff --git a/components/chainhook-sdk/src/indexer/stacks/mod.rs b/components/chainhook-sdk/src/indexer/stacks/mod.rs index 60a65a9ea..4cff47b7f 100644 --- a/components/chainhook-sdk/src/indexer/stacks/mod.rs +++ b/components/chainhook-sdk/src/indexer/stacks/mod.rs @@ -122,63 +122,138 @@ impl NewEvent { if let Some(ref event_data) = self.stx_mint_event { let data: STXMintEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::STXMintEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::STXMintEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.stx_lock_event { let data: STXLockEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::STXLockEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::STXLockEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.stx_burn_event { let data: STXBurnEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::STXBurnEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::STXBurnEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.stx_transfer_event { let data: STXTransferEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::STXTransferEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: StacksTransactionEventPayload::STXTransferEvent(data.clone()), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.nft_mint_event { let data: NFTMintEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::NFTMintEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::NFTMintEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.nft_burn_event { let data: NFTBurnEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::NFTBurnEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::NFTBurnEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.nft_transfer_event { let data: NFTTransferEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::NFTTransferEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: StacksTransactionEventPayload::NFTTransferEvent(data.clone()), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.ft_mint_event { let data: FTMintEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::FTMintEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::FTMintEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.ft_burn_event { let data: FTBurnEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::FTBurnEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::FTBurnEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.ft_transfer_event { let data: FTTransferEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::FTTransferEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::FTTransferEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.data_var_set_event { let data: DataVarSetEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::DataVarSetEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: (StacksTransactionEventPayload::DataVarSetEvent(data)), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.data_map_insert_event { let data: DataMapInsertEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::DataMapInsertEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: StacksTransactionEventPayload::DataMapInsertEvent(data.clone()), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.data_map_update_event { let data: DataMapUpdateEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::DataMapUpdateEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: StacksTransactionEventPayload::DataMapUpdateEvent(data.clone()), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.data_map_delete_event { let data: DataMapDeleteEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::DataMapDeleteEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: StacksTransactionEventPayload::DataMapDeleteEvent(data.clone()), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } else if let Some(ref event_data) = self.contract_event { let data: SmartContractEventData = serde_json::from_value(event_data.clone()).expect("Unable to decode event_data"); - return Ok(StacksTransactionEvent::SmartContractEvent(data.clone())); + return Ok(StacksTransactionEvent { + event_payload: StacksTransactionEventPayload::SmartContractEvent(data.clone()), + position: StacksTransactionEventPosition { + index: self.event_index, + }, + }); } return Err(format!("unable to support event type")); } @@ -842,8 +917,8 @@ pub fn get_standardized_stacks_receipt( if include_operations { let mut operation_id = 0; for event in events.iter() { - match event { - StacksTransactionEvent::STXMintEvent(data) => { + match &event.event_payload { + StacksTransactionEventPayload::STXMintEvent(data) => { operations.push(Operation { operation_identifier: OperationIdentifier { index: operation_id, @@ -864,7 +939,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::STXLockEvent(data) => { + StacksTransactionEventPayload::STXLockEvent(data) => { operations.push(Operation { operation_identifier: OperationIdentifier { index: operation_id, @@ -888,7 +963,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::STXBurnEvent(data) => { + StacksTransactionEventPayload::STXBurnEvent(data) => { operations.push(Operation { operation_identifier: OperationIdentifier { index: operation_id, @@ -909,7 +984,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::STXTransferEvent(data) => { + StacksTransactionEventPayload::STXTransferEvent(data) => { operations.push(Operation { operation_identifier: OperationIdentifier { index: operation_id, @@ -955,7 +1030,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::NFTMintEvent(data) => { + StacksTransactionEventPayload::NFTMintEvent(data) => { let (asset_class_identifier, contract_identifier) = get_mutated_ids(&data.asset_class_identifier); mutated_assets_radius.insert(asset_class_identifier); @@ -983,7 +1058,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::NFTBurnEvent(data) => { + StacksTransactionEventPayload::NFTBurnEvent(data) => { let (asset_class_identifier, contract_identifier) = get_mutated_ids(&data.asset_class_identifier); mutated_assets_radius.insert(asset_class_identifier); @@ -1011,7 +1086,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::NFTTransferEvent(data) => { + StacksTransactionEventPayload::NFTTransferEvent(data) => { let (asset_class_identifier, contract_identifier) = get_mutated_ids(&data.asset_class_identifier); mutated_assets_radius.insert(asset_class_identifier); @@ -1064,7 +1139,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::FTMintEvent(data) => { + StacksTransactionEventPayload::FTMintEvent(data) => { let (asset_class_identifier, contract_identifier) = get_mutated_ids(&data.asset_class_identifier); mutated_assets_radius.insert(asset_class_identifier); @@ -1100,7 +1175,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::FTBurnEvent(data) => { + StacksTransactionEventPayload::FTBurnEvent(data) => { let (asset_class_identifier, contract_identifier) = get_mutated_ids(&data.asset_class_identifier); mutated_assets_radius.insert(asset_class_identifier); @@ -1131,7 +1206,7 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::FTTransferEvent(data) => { + StacksTransactionEventPayload::FTTransferEvent(data) => { let (asset_class_identifier, contract_identifier) = get_mutated_ids(&data.asset_class_identifier); mutated_assets_radius.insert(asset_class_identifier); @@ -1187,11 +1262,11 @@ pub fn get_standardized_stacks_receipt( }); operation_id += 1; } - StacksTransactionEvent::DataVarSetEvent(_data) => {} - StacksTransactionEvent::DataMapInsertEvent(_data) => {} - StacksTransactionEvent::DataMapUpdateEvent(_data) => {} - StacksTransactionEvent::DataMapDeleteEvent(_data) => {} - StacksTransactionEvent::SmartContractEvent(data) => { + StacksTransactionEventPayload::DataVarSetEvent(_data) => {} + StacksTransactionEventPayload::DataMapInsertEvent(_data) => {} + StacksTransactionEventPayload::DataMapUpdateEvent(_data) => {} + StacksTransactionEventPayload::DataMapDeleteEvent(_data) => {} + StacksTransactionEventPayload::SmartContractEvent(data) => { mutated_contracts_radius.insert(data.contract_identifier.clone()); } } diff --git a/components/chainhook-sdk/src/indexer/stacks/tests.rs b/components/chainhook-sdk/src/indexer/stacks/tests.rs index 0793b8602..94f7eb8d7 100644 --- a/components/chainhook-sdk/src/indexer/stacks/tests.rs +++ b/components/chainhook-sdk/src/indexer/stacks/tests.rs @@ -2,7 +2,7 @@ use chainhook_types::{ DataMapDeleteEventData, DataMapInsertEventData, DataMapUpdateEventData, DataVarSetEventData, FTBurnEventData, FTMintEventData, FTTransferEventData, NFTBurnEventData, NFTMintEventData, NFTTransferEventData, STXBurnEventData, STXLockEventData, STXMintEventData, - STXTransferEventData, SmartContractEventData, StacksTransactionEvent, + STXTransferEventData, SmartContractEventData, StacksTransactionEventPayload, }; use crate::indexer::tests::helpers::stacks_events::create_new_event_from_stacks_event; @@ -273,88 +273,88 @@ fn test_stacks_vector_052() { process_stacks_blocks_and_check_expectations(helpers::stacks_shapes::get_vector_052()); } -#[test_case(StacksTransactionEvent::STXTransferEvent(STXTransferEventData { +#[test_case(StacksTransactionEventPayload::STXTransferEvent(STXTransferEventData { sender: format!(""), recipient: format!(""), amount: format!("1"), }); "stx_transfer")] -#[test_case(StacksTransactionEvent::STXMintEvent(STXMintEventData { +#[test_case(StacksTransactionEventPayload::STXMintEvent(STXMintEventData { recipient: format!(""), amount: format!("1"), }); "stx_mint")] -#[test_case(StacksTransactionEvent::STXBurnEvent(STXBurnEventData { +#[test_case(StacksTransactionEventPayload::STXBurnEvent(STXBurnEventData { sender: format!(""), amount: format!("1"), }); "stx_burn")] -#[test_case(StacksTransactionEvent::STXLockEvent(STXLockEventData { +#[test_case(StacksTransactionEventPayload::STXLockEvent(STXLockEventData { locked_amount: format!("1"), unlock_height: format!(""), locked_address: format!(""), }); "stx_lock")] -#[test_case(StacksTransactionEvent::NFTTransferEvent(NFTTransferEventData { +#[test_case(StacksTransactionEventPayload::NFTTransferEvent(NFTTransferEventData { asset_class_identifier: format!(""), hex_asset_identifier: format!(""), sender: format!(""), recipient: format!(""), }); "nft_transfer")] -#[test_case(StacksTransactionEvent::NFTMintEvent(NFTMintEventData { +#[test_case(StacksTransactionEventPayload::NFTMintEvent(NFTMintEventData { asset_class_identifier: format!(""), hex_asset_identifier: format!(""), recipient: format!(""), }); "nft_mint")] -#[test_case(StacksTransactionEvent::NFTBurnEvent(NFTBurnEventData { +#[test_case(StacksTransactionEventPayload::NFTBurnEvent(NFTBurnEventData { asset_class_identifier: format!(""), hex_asset_identifier: format!(""), sender: format!(""), }); "nft_burn")] -#[test_case(StacksTransactionEvent::FTTransferEvent(FTTransferEventData { +#[test_case(StacksTransactionEventPayload::FTTransferEvent(FTTransferEventData { asset_class_identifier: format!(""), sender: format!(""), recipient: format!(""), amount: format!("1"), }); "ft_transfer")] -#[test_case(StacksTransactionEvent::FTMintEvent(FTMintEventData { +#[test_case(StacksTransactionEventPayload::FTMintEvent(FTMintEventData { asset_class_identifier: format!(""), recipient: format!(""), amount: format!("1"), }); "ft_mint")] -#[test_case(StacksTransactionEvent::FTBurnEvent(FTBurnEventData { +#[test_case(StacksTransactionEventPayload::FTBurnEvent(FTBurnEventData { asset_class_identifier: format!(""), sender: format!(""), amount: format!("1"), }); "ft_burn")] -#[test_case(StacksTransactionEvent::DataVarSetEvent(DataVarSetEventData { +#[test_case(StacksTransactionEventPayload::DataVarSetEvent(DataVarSetEventData { contract_identifier: format!(""), var: format!(""), hex_new_value: format!(""), }); "data_var_set")] -#[test_case(StacksTransactionEvent::DataMapInsertEvent(DataMapInsertEventData { +#[test_case(StacksTransactionEventPayload::DataMapInsertEvent(DataMapInsertEventData { contract_identifier: format!(""), hex_inserted_key: format!(""), hex_inserted_value: format!(""), map: format!("") }); "data_map_insert")] -#[test_case(StacksTransactionEvent::DataMapUpdateEvent(DataMapUpdateEventData { +#[test_case(StacksTransactionEventPayload::DataMapUpdateEvent(DataMapUpdateEventData { contract_identifier: format!(""), hex_new_value: format!(""), hex_key: format!(""), map: format!("") }); "data_map_update")] -#[test_case(StacksTransactionEvent::DataMapDeleteEvent(DataMapDeleteEventData { +#[test_case(StacksTransactionEventPayload::DataMapDeleteEvent(DataMapDeleteEventData { contract_identifier: format!(""), hex_deleted_key: format!(""), map: format!("") }); "data_map_delete")] -#[test_case(StacksTransactionEvent::SmartContractEvent(SmartContractEventData { +#[test_case(StacksTransactionEventPayload::SmartContractEvent(SmartContractEventData { contract_identifier: format!(""), topic: format!("print"), hex_value: format!(""), }); "smart_contract_print_event")] -fn new_events_can_be_converted_into_chainhook_event(original_event: StacksTransactionEvent) { +fn new_events_can_be_converted_into_chainhook_event(original_event: StacksTransactionEventPayload) { let new_event = create_new_event_from_stacks_event(original_event.clone()); let event = new_event.into_chainhook_event().unwrap(); let original_event_serialized = serde_json::to_string(&original_event).unwrap(); - let event_serialized = serde_json::to_string(&event).unwrap(); + let event_serialized = serde_json::to_string(&event.event_payload).unwrap(); assert_eq!(original_event_serialized, event_serialized); } diff --git a/components/chainhook-sdk/src/indexer/tests/helpers/stacks_events.rs b/components/chainhook-sdk/src/indexer/tests/helpers/stacks_events.rs index 2e1650248..3db3c9ed3 100644 --- a/components/chainhook-sdk/src/indexer/tests/helpers/stacks_events.rs +++ b/components/chainhook-sdk/src/indexer/tests/helpers/stacks_events.rs @@ -1,94 +1,97 @@ -use chainhook_types::StacksTransactionEvent; +use chainhook_types::StacksTransactionEventPayload; use crate::indexer::stacks::NewEvent; -pub fn create_new_event_from_stacks_event(event: StacksTransactionEvent) -> NewEvent { +pub fn create_new_event_from_stacks_event(event: StacksTransactionEventPayload) -> NewEvent { let mut event_type = String::new(); - let stx_transfer_event = if let StacksTransactionEvent::STXTransferEvent(data) = &event { + let stx_transfer_event = if let StacksTransactionEventPayload::STXTransferEvent(data) = &event { event_type = format!("stx_transfer"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let stx_mint_event = if let StacksTransactionEvent::STXMintEvent(data) = &event { + let stx_mint_event = if let StacksTransactionEventPayload::STXMintEvent(data) = &event { event_type = format!("stx_mint"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let stx_burn_event = if let StacksTransactionEvent::STXBurnEvent(data) = &event { + let stx_burn_event = if let StacksTransactionEventPayload::STXBurnEvent(data) = &event { event_type = format!("stx_burn"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let stx_lock_event = if let StacksTransactionEvent::STXLockEvent(data) = &event { + let stx_lock_event = if let StacksTransactionEventPayload::STXLockEvent(data) = &event { event_type = format!("stx_lock"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let nft_transfer_event = if let StacksTransactionEvent::NFTTransferEvent(data) = &event { + let nft_transfer_event = if let StacksTransactionEventPayload::NFTTransferEvent(data) = &event { event_type = format!("nft_transfer"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let nft_mint_event = if let StacksTransactionEvent::NFTMintEvent(data) = &event { + let nft_mint_event = if let StacksTransactionEventPayload::NFTMintEvent(data) = &event { event_type = format!("nft_mint"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let nft_burn_event = if let StacksTransactionEvent::NFTBurnEvent(data) = &event { + let nft_burn_event = if let StacksTransactionEventPayload::NFTBurnEvent(data) = &event { event_type = format!("nft_burn"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let ft_transfer_event = if let StacksTransactionEvent::FTTransferEvent(data) = &event { + let ft_transfer_event = if let StacksTransactionEventPayload::FTTransferEvent(data) = &event { event_type = format!("ft_transfer"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let ft_mint_event = if let StacksTransactionEvent::FTMintEvent(data) = &event { + let ft_mint_event = if let StacksTransactionEventPayload::FTMintEvent(data) = &event { event_type = format!("ft_mint"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let ft_burn_event = if let StacksTransactionEvent::FTBurnEvent(data) = &event { + let ft_burn_event = if let StacksTransactionEventPayload::FTBurnEvent(data) = &event { event_type = format!("ft_burn"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let data_var_set_event = if let StacksTransactionEvent::DataVarSetEvent(data) = &event { + let data_var_set_event = if let StacksTransactionEventPayload::DataVarSetEvent(data) = &event { event_type = format!("data_var_set"); Some(serde_json::to_value(data).unwrap()) } else { None }; - let data_map_insert_event = if let StacksTransactionEvent::DataMapInsertEvent(data) = &event { - event_type = format!("data_map_insert"); - Some(serde_json::to_value(data).unwrap()) - } else { - None - }; - let data_map_update_event = if let StacksTransactionEvent::DataMapUpdateEvent(data) = &event { - event_type = format!("data_map_update"); - Some(serde_json::to_value(data).unwrap()) - } else { - None - }; - let data_map_delete_event = if let StacksTransactionEvent::DataMapDeleteEvent(data) = &event { - event_type = format!("data_map_delete"); - Some(serde_json::to_value(data).unwrap()) - } else { - None - }; - let contract_event = if let StacksTransactionEvent::SmartContractEvent(data) = &event { + let data_map_insert_event = + if let StacksTransactionEventPayload::DataMapInsertEvent(data) = &event { + event_type = format!("data_map_insert"); + Some(serde_json::to_value(data).unwrap()) + } else { + None + }; + let data_map_update_event = + if let StacksTransactionEventPayload::DataMapUpdateEvent(data) = &event { + event_type = format!("data_map_update"); + Some(serde_json::to_value(data).unwrap()) + } else { + None + }; + let data_map_delete_event = + if let StacksTransactionEventPayload::DataMapDeleteEvent(data) = &event { + event_type = format!("data_map_delete"); + Some(serde_json::to_value(data).unwrap()) + } else { + None + }; + let contract_event = if let StacksTransactionEventPayload::SmartContractEvent(data) = &event { event_type = format!("smart_contract_print_event"); Some(serde_json::to_value(data).unwrap()) } else { diff --git a/components/chainhook-sdk/src/observer/tests/mod.rs b/components/chainhook-sdk/src/observer/tests/mod.rs index 965dc4ca4..7b678d2ce 100644 --- a/components/chainhook-sdk/src/observer/tests/mod.rs +++ b/components/chainhook-sdk/src/observer/tests/mod.rs @@ -1146,8 +1146,12 @@ fn test_bitcoin_chainhook_through_reorg() { inscription_output_value: cursor, inscription_id: format!("{cursor}"), inscription_input_index: 0, - inscription_pointer: 0, + inscription_pointer: None, inscriber_address: None, + metadata: None, + metaprotocol: None, + delegate: None, + parent: None, ordinal_number: cursor, ordinal_block_height: b.block.block_identifier.index, ordinal_offset: 0, diff --git a/components/chainhook-sdk/src/observer/zmq.rs b/components/chainhook-sdk/src/observer/zmq.rs index 30a50592f..5d31a7dea 100644 --- a/components/chainhook-sdk/src/observer/zmq.rs +++ b/components/chainhook-sdk/src/observer/zmq.rs @@ -148,6 +148,7 @@ pub async fn start_zeromq_runloop( "Possible re-org detected, retrieving parent block {parent_block_hash}" ) }); + block_hashes.push_front(block_hash); block_hashes.push_front(parent_block_hash); } } diff --git a/components/chainhook-types-rs/Cargo.toml b/components/chainhook-types-rs/Cargo.toml index da83955e0..a09f1b58c 100644 --- a/components/chainhook-types-rs/Cargo.toml +++ b/components/chainhook-types-rs/Cargo.toml @@ -2,7 +2,7 @@ name = "chainhook-types" description = "Bitcoin and Stacks data schemas, based on the Rosetta specification" license = "MIT" -version = "1.3.1" +version = "1.3.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/components/chainhook-types-rs/src/events.rs b/components/chainhook-types-rs/src/events.rs index c9a65cd19..02179b51b 100644 --- a/components/chainhook-types-rs/src/events.rs +++ b/components/chainhook-types-rs/src/events.rs @@ -123,7 +123,7 @@ pub struct SmartContractEventData { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[serde(tag = "type", content = "data")] -pub enum StacksTransactionEvent { +pub enum StacksTransactionEventPayload { STXTransferEvent(STXTransferEventData), STXMintEvent(STXMintEventData), STXLockEvent(STXLockEventData), @@ -140,3 +140,22 @@ pub enum StacksTransactionEvent { DataMapDeleteEvent(DataMapDeleteEventData), SmartContractEvent(SmartContractEventData), } + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct StacksTransactionEvent { + #[serde(flatten)] + pub event_payload: StacksTransactionEventPayload, + #[serde(default)] + pub position: StacksTransactionEventPosition, +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct StacksTransactionEventPosition { + pub index: u32, +} + +impl Default for StacksTransactionEventPosition { + fn default() -> Self { + Self { index: 0 } + } +} diff --git a/components/chainhook-types-rs/src/rosetta.rs b/components/chainhook-types-rs/src/rosetta.rs index 88d98535d..ef0ab908a 100644 --- a/components/chainhook-types-rs/src/rosetta.rs +++ b/components/chainhook-types-rs/src/rosetta.rs @@ -2,6 +2,7 @@ use super::bitcoin::{TxIn, TxOut}; use crate::contract_interface::ContractInterface; use crate::events::*; use schemars::JsonSchema; +use serde_json::Value; use std::cmp::Ordering; use std::collections::HashSet; use std::fmt::Display; @@ -363,8 +364,12 @@ pub struct OrdinalInscriptionRevealData { pub inscription_output_value: u64, pub inscription_id: String, pub inscription_input_index: usize, - pub inscription_pointer: u64, + pub inscription_pointer: Option, pub inscriber_address: Option, + pub delegate: Option, + pub metaprotocol: Option, + pub metadata: Option, + pub parent: Option, pub ordinal_number: u64, pub ordinal_block_height: u64, pub ordinal_offset: u64, diff --git a/docs/chainhook-openapi.json b/docs/chainhook-openapi.json index b050194dc..c7c4957d0 100644 --- a/docs/chainhook-openapi.json +++ b/docs/chainhook-openapi.json @@ -2,7 +2,7 @@ "openapi": "3.0.0", "info": { "title": "chainhook", - "version": "1.3.0" + "version": "1.3.1" }, "paths": { "/ping": {