diff --git a/creator-keys/src/events.rs b/creator-keys/src/events.rs index 2e45568e..2bfe5569 100644 --- a/creator-keys/src/events.rs +++ b/creator-keys/src/events.rs @@ -258,11 +258,16 @@ pub struct AllocationClaimedEvent { pub ledger: u32, } +/// Stable field order for protocol fee recipient updated event payloads. +pub const PROTOCOL_FEE_RECIPIENT_UPDATED_DATA_FIELDS: [&str; 3] = + ["old_recipient", "new_recipient", "updated_at_ledger"]; + #[derive(Clone, Debug, Eq, PartialEq)] #[contracttype] pub struct ProtocolFeeRecipientUpdatedEvent { pub old_recipient: Address, pub new_recipient: Address, + pub updated_at_ledger: u32, } #[derive(Clone, Debug, Eq, PartialEq)] @@ -431,6 +436,23 @@ pub fn ttl_extended_topics(creator: &Address) -> (Symbol, Address) { (TTL_EXTENDED_EVENT_NAME, creator.clone()) } +/// Stable field order for TTL extension event payloads. +pub const TTL_EXTENDED_DATA_FIELDS: [&str; 3] = + ["creator_id", "extended_at_ledger", "new_expiry_ledger"]; + +/// Stable TTL extension event payload for downstream indexers. +/// +/// Event shape: +/// - topics: `(TTL_EXTENDED_EVENT_NAME, creator_id)` +/// - data: `TtlExtendedEvent` +#[derive(Clone, Debug, Eq, PartialEq)] +#[contracttype] +pub struct TtlExtendedEvent { + pub creator_id: Address, + pub extended_at_ledger: u32, + pub new_expiry_ledger: u32, +} + #[contracterror] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index 1adb1f23..b3faf92f 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -1392,8 +1392,14 @@ fn extend_creator_ttl(env: &Env, creator: &Address) { } } - env.events() - .publish(events::ttl_extended_topics(creator), extend_to); + env.events().publish( + events::ttl_extended_topics(creator), + events::TtlExtendedEvent { + creator_id: creator.clone(), + extended_at_ledger: current_ledger, + new_expiry_ledger: extend_to, + }, + ); } #[contract] @@ -2618,6 +2624,7 @@ impl CreatorKeysContract { events::ProtocolFeeRecipientUpdatedEvent { old_recipient: old, new_recipient: recipient, + updated_at_ledger: env.ledger().sequence(), }, ); } @@ -3019,6 +3026,7 @@ impl CreatorKeysContract { events::ProtocolFeeRecipientUpdatedEvent { old_recipient, new_recipient, + updated_at_ledger: env.ledger().sequence(), }, ); diff --git a/creator-keys/test_snapshots/test_buy_event_buyer_address_field_is_non_zero.1.json b/creator-keys/test_snapshots/test_buy_event_buyer_address_field_is_non_zero.1.json index b6ee78f2..f5aa6331 100644 --- a/creator-keys/test_snapshots/test_buy_event_buyer_address_field_is_non_zero.1.json +++ b/creator-keys/test_snapshots/test_buy_event_buyer_address_field_is_non_zero.1.json @@ -693,7 +693,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_event_buyer_address_matches_caller.1.json b/creator-keys/test_snapshots/test_buy_event_buyer_address_matches_caller.1.json index b6ee78f2..f5aa6331 100644 --- a/creator-keys/test_snapshots/test_buy_event_buyer_address_matches_caller.1.json +++ b/creator-keys/test_snapshots/test_buy_event_buyer_address_matches_caller.1.json @@ -693,7 +693,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_event_includes_payment_amount.1.json b/creator-keys/test_snapshots/test_buy_key_event_includes_payment_amount.1.json index f50dd6cb..8cc11ffb 100644 --- a/creator-keys/test_snapshots/test_buy_key_event_includes_payment_amount.1.json +++ b/creator-keys/test_snapshots/test_buy_key_event_includes_payment_amount.1.json @@ -693,7 +693,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_event_payload_fields_are_validated_from_fixture.1.json b/creator-keys/test_snapshots/test_buy_key_event_payload_fields_are_validated_from_fixture.1.json index f50dd6cb..8cc11ffb 100644 --- a/creator-keys/test_snapshots/test_buy_key_event_payload_fields_are_validated_from_fixture.1.json +++ b/creator-keys/test_snapshots/test_buy_key_event_payload_fields_are_validated_from_fixture.1.json @@ -693,7 +693,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_event_payload_tracks_new_supply_across_purchases.1.json b/creator-keys/test_snapshots/test_buy_key_event_payload_tracks_new_supply_across_purchases.1.json index 463af20c..766bde3e 100644 --- a/creator-keys/test_snapshots/test_buy_key_event_payload_tracks_new_supply_across_purchases.1.json +++ b/creator-keys/test_snapshots/test_buy_key_event_payload_tracks_new_supply_across_purchases.1.json @@ -914,7 +914,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_event_present_after_purchase.1.json b/creator-keys/test_snapshots/test_buy_key_event_present_after_purchase.1.json index b6ee78f2..f5aa6331 100644 --- a/creator-keys/test_snapshots/test_buy_key_event_present_after_purchase.1.json +++ b/creator-keys/test_snapshots/test_buy_key_event_present_after_purchase.1.json @@ -693,7 +693,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_event_topics_include_creator_and_buyer.1.json b/creator-keys/test_snapshots/test_buy_key_event_topics_include_creator_and_buyer.1.json index c02894cf..99c1b7d5 100644 --- a/creator-keys/test_snapshots/test_buy_key_event_topics_include_creator_and_buyer.1.json +++ b/creator-keys/test_snapshots/test_buy_key_event_topics_include_creator_and_buyer.1.json @@ -693,7 +693,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_positive_payment_succeeds.1.json b/creator-keys/test_snapshots/test_buy_key_positive_payment_succeeds.1.json index b6ee78f2..f5aa6331 100644 --- a/creator-keys/test_snapshots/test_buy_key_positive_payment_succeeds.1.json +++ b/creator-keys/test_snapshots/test_buy_key_positive_payment_succeeds.1.json @@ -693,7 +693,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_succeeds_after_unpause.1.json b/creator-keys/test_snapshots/test_buy_key_succeeds_after_unpause.1.json index 5f660f79..b58529a9 100644 --- a/creator-keys/test_snapshots/test_buy_key_succeeds_after_unpause.1.json +++ b/creator-keys/test_snapshots/test_buy_key_succeeds_after_unpause.1.json @@ -930,7 +930,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_with_large_safe_amount_succeeds.1.json b/creator-keys/test_snapshots/test_buy_key_with_large_safe_amount_succeeds.1.json index d8d71595..a7cd1d65 100644 --- a/creator-keys/test_snapshots/test_buy_key_with_large_safe_amount_succeeds.1.json +++ b/creator-keys/test_snapshots/test_buy_key_with_large_safe_amount_succeeds.1.json @@ -636,7 +636,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_key_with_maximum_safe_i128_succeeds.1.json b/creator-keys/test_snapshots/test_buy_key_with_maximum_safe_i128_succeeds.1.json index 17486c55..335f52de 100644 --- a/creator-keys/test_snapshots/test_buy_key_with_maximum_safe_i128_succeeds.1.json +++ b/creator-keys/test_snapshots/test_buy_key_with_maximum_safe_i128_succeeds.1.json @@ -636,7 +636,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_buy_slippage_succeeds_when_price_at_or_below_max_price.1.json b/creator-keys/test_snapshots/test_buy_slippage_succeeds_when_price_at_or_below_max_price.1.json index ba532748..1eb43ba2 100644 --- a/creator-keys/test_snapshots/test_buy_slippage_succeeds_when_price_at_or_below_max_price.1.json +++ b/creator-keys/test_snapshots/test_buy_slippage_succeeds_when_price_at_or_below_max_price.1.json @@ -1211,7 +1211,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_sell_after_buy_succeeds_without_underflow_error.1.json b/creator-keys/test_snapshots/test_sell_after_buy_succeeds_without_underflow_error.1.json index 67aef346..88f30807 100644 --- a/creator-keys/test_snapshots/test_sell_after_buy_succeeds_without_underflow_error.1.json +++ b/creator-keys/test_snapshots/test_sell_after_buy_succeeds_without_underflow_error.1.json @@ -654,7 +654,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_sell_event_seller_address_field_is_non_zero.1.json b/creator-keys/test_snapshots/test_sell_event_seller_address_field_is_non_zero.1.json index 67aef346..88f30807 100644 --- a/creator-keys/test_snapshots/test_sell_event_seller_address_field_is_non_zero.1.json +++ b/creator-keys/test_snapshots/test_sell_event_seller_address_field_is_non_zero.1.json @@ -654,7 +654,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_sell_event_seller_address_matches_caller.1.json b/creator-keys/test_snapshots/test_sell_event_seller_address_matches_caller.1.json index 67aef346..88f30807 100644 --- a/creator-keys/test_snapshots/test_sell_event_seller_address_matches_caller.1.json +++ b/creator-keys/test_snapshots/test_sell_event_seller_address_matches_caller.1.json @@ -654,7 +654,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_sell_key_event_payload_fields_are_validated_from_fixture.1.json b/creator-keys/test_snapshots/test_sell_key_event_payload_fields_are_validated_from_fixture.1.json index 6e8cfae9..e6513864 100644 --- a/creator-keys/test_snapshots/test_sell_key_event_payload_fields_are_validated_from_fixture.1.json +++ b/creator-keys/test_snapshots/test_sell_key_event_payload_fields_are_validated_from_fixture.1.json @@ -767,7 +767,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_sell_key_event_payload_tracks_zero_supply_after_last_sale.1.json b/creator-keys/test_snapshots/test_sell_key_event_payload_tracks_zero_supply_after_last_sale.1.json index 67aef346..88f30807 100644 --- a/creator-keys/test_snapshots/test_sell_key_event_payload_tracks_zero_supply_after_last_sale.1.json +++ b/creator-keys/test_snapshots/test_sell_key_event_payload_tracks_zero_supply_after_last_sale.1.json @@ -654,7 +654,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_sell_slippage_succeeds_when_proceeds_meet_or_exceed_min_proceeds.1.json b/creator-keys/test_snapshots/test_sell_slippage_succeeds_when_proceeds_meet_or_exceed_min_proceeds.1.json index 29b6eefe..4ff5071a 100644 --- a/creator-keys/test_snapshots/test_sell_slippage_succeeds_when_proceeds_meet_or_exceed_min_proceeds.1.json +++ b/creator-keys/test_snapshots/test_sell_slippage_succeeds_when_proceeds_meet_or_exceed_min_proceeds.1.json @@ -1179,7 +1179,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_sell_two_keys_succeeds_without_underflow_error.1.json b/creator-keys/test_snapshots/test_sell_two_keys_succeeds_without_underflow_error.1.json index dc5ce1a5..40cdb053 100644 --- a/creator-keys/test_snapshots/test_sell_two_keys_succeeds_without_underflow_error.1.json +++ b/creator-keys/test_snapshots/test_sell_two_keys_succeeds_without_underflow_error.1.json @@ -772,7 +772,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/test_snapshots/test_slippage_none_passthrough_preserves_existing_behavior.1.json b/creator-keys/test_snapshots/test_slippage_none_passthrough_preserves_existing_behavior.1.json index d8e4c283..a1229ae2 100644 --- a/creator-keys/test_snapshots/test_slippage_none_passthrough_preserves_existing_behavior.1.json +++ b/creator-keys/test_snapshots/test_slippage_none_passthrough_preserves_existing_behavior.1.json @@ -941,7 +941,32 @@ } ], "data": { - "u32": 6311520 + "map": [ + { + "key": { + "symbol": "creator_id" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "extended_at_ledger" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "new_expiry_ledger" + }, + "val": { + "u32": 6311520 + } + } + ] } } } diff --git a/creator-keys/tests/contract_test_env/mod.rs b/creator-keys/tests/contract_test_env/mod.rs index 4172695e..b71156c7 100644 --- a/creator-keys/tests/contract_test_env/mod.rs +++ b/creator-keys/tests/contract_test_env/mod.rs @@ -12,8 +12,8 @@ use creator_keys::{constants, CreatorKeysContract, CreatorKeysContractClient}; use soroban_sdk::{ - testutils::{Address as _, Ledger}, - Address, Env, IntoVal, String, Val, + testutils::{Address as _, Events, Ledger}, + Address, Env, IntoVal, String, Val, Vec, }; use std::string::String as StdString; @@ -505,3 +505,40 @@ pub fn compute_expected_holder_dividend( let per_key = net_amount / total_supply as i128; per_key * holder_balance as i128 } + +/// Finds the most recent event emitted by `contract_id` matching `topics` and asserts +/// its decoded data equals `expected_data`. +/// +/// Filtering by contract id and topics (rather than just topics) keeps assertions +/// correct in tests that register more than one contract instance. Panics with a +/// message naming the contract, topics, and the expected/actual payloads when no +/// matching event exists or the decoded data doesn't match, so a field-level +/// regression on any event is easy to diagnose from the test output alone. +pub fn assert_event(env: &Env, contract_id: &Address, topics: Topics, expected_data: T) +where + Topics: IntoVal> + core::fmt::Debug, + T: PartialEq + core::fmt::Debug, + Val: IntoVal, +{ + let expected_topics: Vec = topics.into_val(env); + + let all_events = env.events().all(); + let matching = all_events + .iter() + .rev() + .find(|(id, event_topics, _)| id == contract_id && *event_topics == expected_topics); + + let (_, _, data) = matching.unwrap_or_else(|| { + panic!( + "no event found for contract={contract_id:?} topics={expected_topics:?}; \ + recorded events={all_events:?}" + ) + }); + + let actual_data: T = data.into_val(env); + assert_eq!( + actual_data, expected_data, + "event data mismatch for contract={contract_id:?} topics={expected_topics:?}: \ + expected {expected_data:?}, got {actual_data:?}" + ); +} diff --git a/creator-keys/tests/protocol_fee_recipient_updated_event.rs b/creator-keys/tests/protocol_fee_recipient_updated_event.rs index 145f3487..3b33d72e 100644 --- a/creator-keys/tests/protocol_fee_recipient_updated_event.rs +++ b/creator-keys/tests/protocol_fee_recipient_updated_event.rs @@ -5,11 +5,11 @@ //! //! Event shape emitted by `update_protocol_fee_recipient`: //! - topics: `(PROTOCOL_FEE_RECIPIENT_UPDATED_EVENT_NAME, admin)` -//! - data: `ProtocolFeeRecipientUpdatedEvent { old_recipient, new_recipient }` +//! - data: `ProtocolFeeRecipientUpdatedEvent { old_recipient, new_recipient, updated_at_ledger }` mod contract_test_env; -use contract_test_env::{register_creator_keys, test_env_with_auths}; +use contract_test_env::{assert_event, register_creator_keys, test_env_with_auths}; use creator_keys::events; use soroban_sdk::{ testutils::{Address as _, Events}, @@ -23,8 +23,9 @@ fn setup_update( Address, Address, Address, + Address, ) { - let (client, _) = register_creator_keys(env); + let (client, contract_id) = register_creator_keys(env); let admin = Address::generate(env); let old_recipient = Address::generate(env); let new_recipient = Address::generate(env); @@ -33,7 +34,7 @@ fn setup_update( client.set_protocol_fee_recipient(&admin, &old_recipient); client.update_protocol_fee_recipient(&admin, &new_recipient); - (client, admin, old_recipient, new_recipient) + (client, contract_id, admin, old_recipient, new_recipient) } fn last_event_data(env: &Env) -> events::ProtocolFeeRecipientUpdatedEvent { @@ -45,7 +46,7 @@ fn last_event_data(env: &Env) -> events::ProtocolFeeRecipientUpdatedEvent { #[test] fn test_protocol_fee_recipient_updated_event_old_recipient_field() { let env = test_env_with_auths(); - let (_, _, old_recipient, _) = setup_update(&env); + let (_, _, _, old_recipient, _) = setup_update(&env); let payload = last_event_data(&env); assert_eq!( @@ -57,7 +58,7 @@ fn test_protocol_fee_recipient_updated_event_old_recipient_field() { #[test] fn test_protocol_fee_recipient_updated_event_new_recipient_field() { let env = test_env_with_auths(); - let (_, _, _, new_recipient) = setup_update(&env); + let (_, _, _, _, new_recipient) = setup_update(&env); let payload = last_event_data(&env); assert_eq!( @@ -66,10 +67,31 @@ fn test_protocol_fee_recipient_updated_event_new_recipient_field() { ); } +#[test] +fn test_protocol_fee_recipient_updated_event_updated_at_ledger_field() { + let env = test_env_with_auths(); + let ledger_before_update = env.ledger().sequence(); + let (_, contract_id, admin, old_recipient, new_recipient) = setup_update(&env); + + assert_event( + &env, + &contract_id, + ( + events::PROTOCOL_FEE_RECIPIENT_UPDATED_EVENT_NAME, + admin.clone(), + ), + events::ProtocolFeeRecipientUpdatedEvent { + old_recipient, + new_recipient, + updated_at_ledger: ledger_before_update, + }, + ); +} + #[test] fn test_protocol_fee_recipient_updated_event_emitted_once_per_update() { let env = test_env_with_auths(); - let (_, _, old_recipient, _) = setup_update(&env); + let (_, _, _, old_recipient, _) = setup_update(&env); let all_events = env.events().all(); let update_event_count = all_events diff --git a/creator-keys/tests/ttl_extension_on_buy.rs b/creator-keys/tests/ttl_extension_on_buy.rs index e5252af0..c8e0bc66 100644 --- a/creator-keys/tests/ttl_extension_on_buy.rs +++ b/creator-keys/tests/ttl_extension_on_buy.rs @@ -5,7 +5,9 @@ mod contract_test_env; -use contract_test_env::{register_creator_keys, register_test_creator, set_key_price_for_tests}; +use contract_test_env::{ + assert_event, register_creator_keys, register_test_creator, set_key_price_for_tests, +}; use creator_keys::constants::storage; use creator_keys::events::{self, ttl_extended_topics}; use creator_keys::CREATOR_TTL_LEDGERS; @@ -90,7 +92,7 @@ fn test_ttl_extension_event_topics_and_payload() { assert_eq!(result, Ok(Ok(1)), "buy should succeed"); let events = env.events().all(); - let (topics, data) = events + let (topics, _) = events .iter() .rev() .find_map(|(_, topics, data)| { @@ -109,9 +111,17 @@ fn test_ttl_extension_event_topics_and_payload() { let topic1: Address = topics.get(1).unwrap().into_val(&env); assert_eq!(topic1, creator); - let extend_to: u32 = data.into_val(&env); - let expected_extend_to = ledger_before_buy + CREATOR_TTL_LEDGERS; - assert_eq!(extend_to, expected_extend_to); + let expected_new_expiry_ledger = ledger_before_buy + CREATOR_TTL_LEDGERS; + assert_event( + &env, + &contract_id, + ttl_extended_topics(&creator), + events::TtlExtendedEvent { + creator_id: creator.clone(), + extended_at_ledger: ledger_before_buy, + new_expiry_ledger: expected_new_expiry_ledger, + }, + ); } /// Second buy on the same ledger does NOT further extend TTL