@layerzerolabs/protocol-stellar-v2 0.2.20 → 0.2.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/.turbo/turbo-build.log +783 -802
  2. package/.turbo/turbo-lint.log +320 -157
  3. package/.turbo/turbo-test.log +1414 -1457
  4. package/Cargo.lock +109 -108
  5. package/Cargo.toml +32 -18
  6. package/contracts/common-macros/Cargo.toml +7 -7
  7. package/contracts/common-macros/src/auth.rs +18 -37
  8. package/contracts/common-macros/src/contract_ttl.rs +2 -2
  9. package/contracts/common-macros/src/lib.rs +27 -10
  10. package/contracts/common-macros/src/lz_contract.rs +38 -7
  11. package/contracts/common-macros/src/storage.rs +251 -292
  12. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +6 -12
  13. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +12 -17
  14. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +2 -7
  15. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +20 -9
  16. package/contracts/common-macros/src/tests/upgradeable.rs +26 -4
  17. package/contracts/common-macros/src/ttl_configurable.rs +2 -10
  18. package/contracts/common-macros/src/ttl_extendable.rs +2 -10
  19. package/contracts/common-macros/src/upgradeable.rs +56 -15
  20. package/contracts/common-macros/src/utils.rs +0 -9
  21. package/contracts/endpoint-v2/src/lib.rs +3 -2
  22. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +2 -2
  23. package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +3 -3
  24. package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +4 -4
  25. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +17 -5
  26. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
  27. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +2 -2
  28. package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +2 -2
  29. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +6 -6
  30. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +67 -37
  31. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +5 -5
  32. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +44 -54
  33. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +7 -7
  34. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +8 -8
  35. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +3 -3
  36. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +4 -4
  37. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +3 -3
  38. package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +2 -2
  39. package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +3 -3
  40. package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +2 -2
  41. package/contracts/layerzero-views/Cargo.toml +0 -1
  42. package/contracts/layerzero-views/src/layerzero_view.rs +1 -13
  43. package/contracts/macro-integration-tests/Cargo.toml +5 -15
  44. package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +48 -0
  45. package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +170 -0
  46. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +154 -0
  47. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +338 -0
  48. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +435 -0
  49. package/contracts/macro-integration-tests/tests/runtime.rs +1 -0
  50. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.rs +8 -0
  51. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -0
  52. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.rs +8 -0
  53. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.stderr +71 -0
  54. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.rs +10 -0
  55. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +5 -0
  56. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.rs +8 -0
  57. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -0
  58. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.rs +8 -0
  59. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -0
  60. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +38 -0
  61. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +96 -0
  62. package/contracts/macro-integration-tests/tests/ui/oapp/pass/minimal_contract.rs +64 -0
  63. package/contracts/macro-integration-tests/tests/ui/oapp/pass/struct_with_fields.rs +46 -0
  64. package/contracts/macro-integration-tests/tests/ui/ownable/fail/only_auth_missing_env.stderr +8 -0
  65. package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +1 -1
  66. package/contracts/macro-integration-tests/tests/ui/ownable/pass/only_auth_env_param_variants.rs +1 -1
  67. package/contracts/macro-integration-tests/tests/ui_oapp.rs +11 -0
  68. package/contracts/message-libs/message-lib-common/Cargo.toml +0 -1
  69. package/contracts/message-libs/message-lib-common/src/errors.rs +1 -1
  70. package/contracts/message-libs/treasury/Cargo.toml +0 -2
  71. package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +2 -2
  72. package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +2 -2
  73. package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +2 -2
  74. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +2 -2
  75. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +2 -2
  76. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +2 -2
  77. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +7 -27
  78. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +2 -2
  79. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +2 -2
  80. package/contracts/oapps/counter/Cargo.toml +4 -6
  81. package/contracts/oapps/counter/integration_tests/utils.rs +19 -12
  82. package/contracts/oapps/oapp/src/errors.rs +1 -1
  83. package/contracts/oapps/oapp/src/interfaces/mod.rs +3 -0
  84. package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +47 -0
  85. package/contracts/oapps/oapp/src/lib.rs +1 -0
  86. package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +4 -4
  87. package/contracts/oapps/oapp/src/oapp_core.rs +5 -5
  88. package/contracts/oapps/oapp/src/oapp_options_type3.rs +12 -4
  89. package/contracts/oapps/oapp/src/oapp_receiver.rs +14 -9
  90. package/contracts/oapps/oapp/src/tests/mod.rs +4 -4
  91. package/contracts/oapps/oapp/src/tests/{test_oapp_core.rs → oapp_core.rs} +4 -4
  92. package/contracts/oapps/oapp/src/tests/{test_oapp_options_type3.rs → oapp_options_type3.rs} +3 -4
  93. package/contracts/oapps/oapp-macros/Cargo.toml +8 -4
  94. package/contracts/oapps/oapp-macros/src/generators.rs +9 -34
  95. package/contracts/oapps/oapp-macros/src/lib.rs +3 -0
  96. package/contracts/oapps/oapp-macros/src/tests/mod.rs +2 -0
  97. package/contracts/oapps/oapp-macros/src/tests/oapp.rs +88 -0
  98. package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +86 -0
  99. package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +103 -0
  100. package/contracts/oapps/oft/integration-tests/utils.rs +28 -8
  101. package/contracts/oapps/oft/src/extensions/oft_fee.rs +136 -74
  102. package/contracts/oapps/oft/src/extensions/pausable.rs +44 -10
  103. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +170 -130
  104. package/contracts/oapps/oft/src/oft.rs +19 -12
  105. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +1 -1
  106. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +1 -1
  107. package/contracts/oapps/oft-core/Cargo.toml +1 -4
  108. package/contracts/oapps/oft-core/integration-tests/setup.rs +2 -2
  109. package/contracts/oapps/oft-core/integration-tests/utils.rs +21 -3
  110. package/contracts/oapps/oft-core/src/errors.rs +3 -2
  111. package/contracts/oapps/oft-core/src/events.rs +6 -0
  112. package/contracts/oapps/oft-core/src/lib.rs +1 -1
  113. package/contracts/oapps/oft-core/src/oft_core.rs +115 -60
  114. package/contracts/oapps/oft-core/src/storage.rs +7 -3
  115. package/contracts/oapps/oft-core/src/tests/mod.rs +1 -0
  116. package/contracts/oapps/oft-core/src/tests/test_decimals.rs +37 -2
  117. package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +2 -2
  118. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +323 -0
  119. package/contracts/oapps/oft-core/src/tests/test_send.rs +2 -2
  120. package/contracts/oapps/oft-core/src/tests/test_utils.rs +59 -14
  121. package/contracts/utils/Cargo.toml +0 -1
  122. package/contracts/utils/src/errors.rs +1 -1
  123. package/contracts/utils/src/multisig.rs +17 -8
  124. package/contracts/utils/src/ownable.rs +6 -6
  125. package/contracts/utils/src/testing_utils.rs +124 -54
  126. package/contracts/utils/src/tests/multisig.rs +12 -12
  127. package/contracts/utils/src/tests/ownable.rs +6 -6
  128. package/contracts/utils/src/tests/testing_utils.rs +50 -167
  129. package/contracts/utils/src/tests/ttl_configurable.rs +5 -5
  130. package/contracts/utils/src/tests/upgradeable.rs +1 -1
  131. package/contracts/utils/src/ttl_configurable.rs +10 -4
  132. package/contracts/utils/src/upgradeable.rs +5 -5
  133. package/contracts/workers/dvn/Cargo.toml +5 -6
  134. package/contracts/workers/dvn/src/dvn.rs +2 -12
  135. package/contracts/workers/dvn-fee-lib/Cargo.toml +1 -1
  136. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +37 -19
  137. package/contracts/workers/dvn-fee-lib/src/lib.rs +12 -2
  138. package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +15 -13
  139. package/contracts/workers/executor/Cargo.toml +3 -0
  140. package/contracts/workers/executor/src/executor.rs +2 -12
  141. package/contracts/workers/executor/src/lib.rs +2 -2
  142. package/contracts/workers/executor/src/tests/auth.rs +394 -0
  143. package/contracts/workers/executor/src/tests/executor.rs +410 -0
  144. package/contracts/workers/executor/src/tests/mod.rs +3 -0
  145. package/contracts/workers/executor/src/tests/setup.rs +250 -0
  146. package/contracts/workers/executor-fee-lib/Cargo.toml +5 -0
  147. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +1 -12
  148. package/contracts/workers/executor-fee-lib/src/lib.rs +8 -2
  149. package/contracts/workers/executor-helper/Cargo.toml +0 -1
  150. package/contracts/workers/price-feed/Cargo.toml +5 -0
  151. package/contracts/workers/price-feed/src/lib.rs +9 -4
  152. package/contracts/workers/price-feed/src/price_feed.rs +1 -11
  153. package/contracts/workers/worker/src/errors.rs +1 -1
  154. package/contracts/workers/worker/src/tests/setup.rs +1 -1
  155. package/contracts/workers/worker/src/tests/worker.rs +55 -41
  156. package/contracts/workers/worker/src/worker.rs +34 -25
  157. package/docs/error-spec.md +55 -0
  158. package/docs/layerzero-v2-on-stellar.md +447 -0
  159. package/docs/oapp-guide.md +212 -0
  160. package/docs/oft-guide.md +314 -0
  161. package/package.json +3 -3
  162. package/sdk/.turbo/turbo-test.log +260 -257
  163. package/sdk/dist/generated/bml.d.ts +3 -3
  164. package/sdk/dist/generated/bml.js +4 -4
  165. package/sdk/dist/generated/counter.d.ts +295 -295
  166. package/sdk/dist/generated/counter.js +43 -43
  167. package/sdk/dist/generated/dvn.d.ts +91 -91
  168. package/sdk/dist/generated/dvn.js +24 -24
  169. package/sdk/dist/generated/dvn_fee_lib.d.ts +92 -92
  170. package/sdk/dist/generated/dvn_fee_lib.js +25 -25
  171. package/sdk/dist/generated/endpoint.d.ts +99 -99
  172. package/sdk/dist/generated/endpoint.js +16 -16
  173. package/sdk/dist/generated/executor.d.ts +91 -91
  174. package/sdk/dist/generated/executor.js +24 -24
  175. package/sdk/dist/generated/executor_fee_lib.d.ts +92 -92
  176. package/sdk/dist/generated/executor_fee_lib.js +25 -25
  177. package/sdk/dist/generated/executor_helper.d.ts +3 -3
  178. package/sdk/dist/generated/executor_helper.js +4 -4
  179. package/sdk/dist/generated/layerzero_view.d.ts +186 -186
  180. package/sdk/dist/generated/layerzero_view.js +35 -35
  181. package/sdk/dist/generated/oft.d.ts +366 -352
  182. package/sdk/dist/generated/oft.js +74 -79
  183. package/sdk/dist/generated/price_feed.d.ts +198 -198
  184. package/sdk/dist/generated/price_feed.js +39 -39
  185. package/sdk/dist/generated/sml.d.ts +99 -99
  186. package/sdk/dist/generated/sml.js +16 -16
  187. package/sdk/dist/generated/treasury.d.ts +99 -99
  188. package/sdk/dist/generated/treasury.js +16 -16
  189. package/sdk/dist/generated/uln302.d.ts +99 -99
  190. package/sdk/dist/generated/uln302.js +16 -16
  191. package/sdk/dist/generated/upgrader.d.ts +3 -3
  192. package/sdk/dist/generated/upgrader.js +3 -3
  193. package/sdk/package.json +1 -1
  194. package/sdk/test/suites/localnet.ts +84 -20
  195. package/contracts/ERROR_SPEC.md +0 -51
  196. package/contracts/endpoint-v2/ARCHITECTURE.md +0 -233
  197. /package/contracts/oapps/oapp/src/tests/{test_oapp_receiver.rs → oapp_receiver.rs} +0 -0
  198. /package/contracts/oapps/oapp/src/tests/{test_oapp_sender.rs → oapp_sender.rs} +0 -0
@@ -1,26 +1,76 @@
1
- use soroban_sdk::{testutils::Events, xdr::ToXdr, Address, Env, Event, Val, Vec};
1
+ use soroban_sdk::{testutils::Events, xdr, Address, Env, Event, TryFromVal, Val, Vec};
2
2
 
3
- fn topics_eq(env: &Env, a: &Vec<Val>, b: &Vec<Val>) -> bool {
4
- if a.len() != b.len() {
5
- return false;
6
- }
7
- for i in 0..a.len() {
8
- let av = a.get(i).unwrap();
9
- let bv = b.get(i).unwrap();
10
- // Compare XDR serialization for deep value equality
11
- if av.to_xdr(env) != bv.to_xdr(env) {
12
- return false;
13
- }
3
+ /// Decodes a raw emitted contract event (XDR) into `(topics, data)`.
4
+ ///
5
+ /// Soroban testutils exposes events as [`ContractEvents`](soroban_sdk::testutils::ContractEvents),
6
+ /// which internally stores XDR [`ContractEvent`](soroban_sdk::xdr::ContractEvent) values.
7
+ /// This helper converts the XDR topics/data into `soroban_sdk::Val` so tests can inspect
8
+ /// topics and data using normal Soroban conversions (`TryFromVal` / `IntoVal`).
9
+ ///
10
+ /// Returns `None` if any topic or the data payload can't be converted into `Val` for the
11
+ /// provided `Env`.
12
+ ///
13
+ /// # Example
14
+ /// ```ignore
15
+ /// let events = env.events().all().filter_by_contract(&contract);
16
+ /// for ev in events.events().iter() {
17
+ /// let (topics, data) = utils::testing_utils::decode_event_topics_data(&env, ev).unwrap();
18
+ /// // ... inspect topics/data ...
19
+ /// }
20
+ /// ```
21
+ pub fn decode_event_topics_data(env: &Env, event: &xdr::ContractEvent) -> Option<(Vec<Val>, Val)> {
22
+ // In the current Soroban SDK version this is always `V0`.
23
+ // Using a single-variant match avoids "irrefutable let-else" warnings.
24
+ let v0 = match &event.body {
25
+ xdr::ContractEventBody::V0(v0) => v0,
26
+ };
27
+
28
+ let mut topics = Vec::<Val>::new(env);
29
+ for t in v0.topics.iter() {
30
+ topics.push_back(Val::try_from_val(env, t).ok()?);
14
31
  }
15
- true
32
+ let data = Val::try_from_val(env, &v0.data).ok()?;
33
+ Some((topics, data))
16
34
  }
17
35
 
18
- fn data_eq(env: &Env, a: &Val, b: &Val) -> bool {
19
- // Compare XDR serialization for deep value equality
20
- a.to_xdr(env) == b.to_xdr(env)
36
+ /// Asserts that the environment emitted exactly one event: `expected`.
37
+ ///
38
+ /// This is a **strict equality** assertion over `env.events().all()`:
39
+ /// the full event list must be exactly `[expected]` (no extra events).
40
+ ///
41
+ /// Uses the event struct's `.topics()` and `.data()` methods (generated by `#[contractevent]`)
42
+ /// to compare against emitted events. No more hardcoding topic names or field keys!
43
+ ///
44
+ /// # Example
45
+ /// ```ignore
46
+ /// use crate::events::OwnershipTransferred;
47
+ ///
48
+ /// let expected = OwnershipTransferred {
49
+ /// previous_owner: owner.clone(),
50
+ /// new_owner: new_owner.clone(),
51
+ /// };
52
+ /// assert_eq_event(&env, &contract, expected);
53
+ /// ```
54
+ pub fn assert_eq_event<E: Event>(env: &Env, contract: &Address, expected: E) {
55
+ // Compare against the emitted `xdr::ContractEvent` directly. This avoids the
56
+ // `xdr -> Val` roundtrip and ensures we match exactly what was emitted.
57
+ //
58
+ // IMPORTANT: This asserts *equality* (not "contains").
59
+ extern crate std;
60
+
61
+ assert_eq!(
62
+ env.events().all(),
63
+ std::vec![expected.to_xdr(env, contract)],
64
+ "Expected exactly one event. Expected topics: {:?}, data: {:?}",
65
+ expected.topics(env),
66
+ expected.data(env),
67
+ );
21
68
  }
22
69
 
23
- /// Asserts that an event matching the expected event was emitted from the contract.
70
+ /// Asserts that the contract emitted an event equal to `expected`.
71
+ ///
72
+ /// This is a **contains** assertion: after filtering events by `contract`,
73
+ /// `expected` must appear at least once (order doesn't matter; extra events allowed).
24
74
  ///
25
75
  /// Uses the event struct's `.topics()` and `.data()` methods (generated by `#[contractevent]`)
26
76
  /// to compare against emitted events. No more hardcoding topic names or field keys!
@@ -33,68 +83,86 @@ fn data_eq(env: &Env, a: &Val, b: &Val) -> bool {
33
83
  /// previous_owner: owner.clone(),
34
84
  /// new_owner: new_owner.clone(),
35
85
  /// };
36
- /// assert_event(&env, &contract, expected);
86
+ /// assert_eq_event(&env, &contract, expected);
37
87
  /// ```
38
- pub fn assert_event<E: Event>(env: &Env, contract: &Address, expected: E) {
39
- let events = env.events().all();
40
- let expected_topics: Vec<Val> = expected.topics(env);
41
- let expected_data: Val = expected.data(env);
88
+ pub fn assert_contains_event<E: Event>(env: &Env, contract: &Address, expected: E) {
89
+ // Compare against the emitted `xdr::ContractEvent` directly. This avoids the
90
+ // `xdr -> Val` roundtrip and ensures we match exactly what was emitted.
91
+ let expected_xdr = expected.to_xdr(env, contract);
42
92
 
93
+ let events = env.events().all().filter_by_contract(contract);
43
94
  let mut found = false;
44
- for (address, topics, data) in events.iter() {
45
- if &address == contract && topics_eq(env, &topics, &expected_topics) && data_eq(env, &data, &expected_data) {
95
+ for event in events.events().iter() {
96
+ if *event == expected_xdr {
46
97
  found = true;
47
98
  break;
48
99
  }
49
100
  }
50
101
 
51
- assert!(found, "Expected event not found. Expected topics: {:?}, data: {:?}", expected_topics, expected_data);
102
+ assert!(
103
+ found,
104
+ "Expected event not found. Expected topics: {:?}, data: {:?}",
105
+ expected.topics(env),
106
+ expected.data(env)
107
+ );
52
108
  }
53
109
 
54
- /// A helper struct to hold event topics and data for batch assertion with mixed event types.
55
- pub struct ExpectedEvent {
56
- pub topics: Vec<Val>,
57
- pub data: Val,
58
- }
110
+ /// Asserts that the environment emitted events that match `expected_events` exactly.
111
+ ///
112
+ /// This is a **strict equality** assertion over `env.events().all()`:
113
+ /// the full event list must match `expected_events` **in order** and **count**
114
+ /// (no missing/extra events).
115
+ ///
116
+ /// # Example
117
+ /// ```ignore
118
+ /// assert_eq_events(env, &contract, &[
119
+ /// &Event1 { ... },
120
+ /// &Event2 { ... },
121
+ /// ]);
122
+ /// ```
59
123
 
60
- pub trait IntoExpectedEvent: Event + Sized {
61
- fn expected(self, env: &Env) -> ExpectedEvent {
62
- ExpectedEvent { topics: self.topics(env), data: self.data(env) }
63
- }
64
- }
124
+ pub fn assert_eq_events(env: &Env, contract: &Address, expected_events: &[&dyn Event]) {
125
+ // Note: this module is only compiled for tests / testutils usage, where `std` is available.
126
+ extern crate std;
127
+ let expected_xdrs: std::vec::Vec<xdr::ContractEvent> =
128
+ expected_events.iter().map(|e| e.to_xdr(env, contract)).collect();
65
129
 
66
- // Blanket implementation for all Event types
67
- impl<E: Event> IntoExpectedEvent for E {}
130
+ assert_eq!(env.events().all(), expected_xdrs, "Expected events to match exactly");
131
+ }
68
132
 
69
- /// Asserts that all expected events were emitted from the contract (in any order).
70
- /// Use this when asserting multiple events of different types.
133
+ /// Asserts that all `expected_events` were emitted by the contract (in any order).
134
+ ///
135
+ /// This is a **contains** assertion with multiset semantics: after filtering events by
136
+ /// `contract`, every expected event must be present, and duplicates in `expected_events`
137
+ /// require duplicate emissions. Extra emitted events are allowed.
71
138
  ///
72
139
  /// # Example
73
140
  /// ```ignore
74
- /// use utils::testing_utils::IntoExpectedEvent;
75
- ///
76
- /// assert_events(env, &contract, &[
77
- /// Event1 { ... }.expected(env),
78
- /// Event2 { ... }.expected(env),
141
+ /// assert_eq_events(env, &contract, &[
142
+ /// &Event1 { ... },
143
+ /// &Event2 { ... },
79
144
  /// ]);
80
145
  /// ```
81
- pub fn assert_events(env: &Env, contract: &Address, expected_events: &[ExpectedEvent]) {
82
- let events = env.events().all();
83
- // Track which emitted events have already been matched so that duplicate expectations
84
- // require duplicate emissions (multiset semantics).
85
- //
146
+
147
+ pub fn assert_contains_events(env: &Env, contract: &Address, expected_events: &[&dyn Event]) {
86
148
  // Note: this module is only compiled for tests / testutils usage, where `std` is available.
87
149
  extern crate std;
88
- let mut used: std::vec::Vec<bool> = std::vec![false; events.len() as usize];
150
+ let events = env.events().all().filter_by_contract(contract);
151
+ let raw_events = events.events();
152
+ // Track which emitted events have already been matched so that duplicate expectations
153
+ // require duplicate emissions (multiset semantics).
154
+ // We use a `std::vec::Vec<bool>` as a "used" mask to implement multiset matching.
155
+ let mut used: std::vec::Vec<bool> = std::vec![false; raw_events.len()];
89
156
 
90
157
  for (i, expected) in expected_events.iter().enumerate() {
158
+ let expected_xdr = expected.to_xdr(env, contract);
159
+
91
160
  let mut found = false;
92
- for (idx, (address, topics, data)) in events.iter().enumerate() {
161
+ for (idx, event) in raw_events.iter().enumerate() {
93
162
  if used[idx] {
94
163
  continue;
95
164
  }
96
- if &address == contract && topics_eq(env, &topics, &expected.topics) && data_eq(env, &data, &expected.data)
97
- {
165
+ if *event == expected_xdr {
98
166
  used[idx] = true;
99
167
  found = true;
100
168
  break;
@@ -104,7 +172,9 @@ pub fn assert_events(env: &Env, contract: &Address, expected_events: &[ExpectedE
104
172
  assert!(
105
173
  found,
106
174
  "Expected event #{} not found. Expected topics: {:?}, data: {:?}",
107
- i, expected.topics, expected.data
175
+ i,
176
+ expected.topics(env),
177
+ expected.data(env)
108
178
  );
109
179
  }
110
180
  }
@@ -9,6 +9,8 @@ use soroban_sdk::{
9
9
  vec, Address, BytesN, Env, IntoVal, Symbol, TryIntoVal, Val, Vec,
10
10
  };
11
11
 
12
+ use crate::testing_utils::decode_event_topics_data;
13
+
12
14
  // Test contract implementing Multisig + Auth (self-owning)
13
15
  #[contract]
14
16
  pub struct TestContract;
@@ -60,14 +62,13 @@ fn assert_auth(env: &Env, contract: &Address, func: &str, expected_args: Vec<Val
60
62
 
61
63
  fn assert_signer_set_event(env: &Env, contract: &Address, signer: &BytesN<20>, active: bool) {
62
64
  use soroban_sdk::Map;
63
- let events = env.events().all();
65
+ let events = env.events().all().filter_by_contract(contract);
64
66
  // Find the signer_set event for this contract (snake_case event name)
65
- let found = events.iter().any(|event| {
66
- if &event.0 != contract {
67
+ let found = events.events().iter().any(|event| {
68
+ let Some((topics, data)) = decode_event_topics_data(env, event) else {
67
69
  return false;
68
- }
70
+ };
69
71
  // Check topics: ["signer_set", signer]
70
- let topics = &event.1;
71
72
  if topics.len() != 2 {
72
73
  return false;
73
74
  }
@@ -77,7 +78,7 @@ fn assert_signer_set_event(env: &Env, contract: &Address, signer: &BytesN<20>, a
77
78
  return false;
78
79
  }
79
80
  // Check data is a map with "active" field
80
- let data_map: Map<Symbol, bool> = event.2.try_into_val(env).unwrap();
81
+ let data_map: Map<Symbol, bool> = data.try_into_val(env).unwrap();
81
82
  data_map.get(Symbol::new(env, "active")) == Some(active)
82
83
  });
83
84
  assert!(found, "signer_set event not found");
@@ -85,14 +86,13 @@ fn assert_signer_set_event(env: &Env, contract: &Address, signer: &BytesN<20>, a
85
86
 
86
87
  fn assert_threshold_set_event(env: &Env, contract: &Address, threshold: u32) {
87
88
  use soroban_sdk::Map;
88
- let events = env.events().all();
89
+ let events = env.events().all().filter_by_contract(contract);
89
90
  // Find the threshold_set event for this contract (snake_case event name)
90
- let found = events.iter().any(|event| {
91
- if &event.0 != contract {
91
+ let found = events.events().iter().any(|event| {
92
+ let Some((topics, data)) = decode_event_topics_data(env, event) else {
92
93
  return false;
93
- }
94
+ };
94
95
  // Check topics: ["threshold_set"]
95
- let topics = &event.1;
96
96
  if topics.len() != 1 {
97
97
  return false;
98
98
  }
@@ -101,7 +101,7 @@ fn assert_threshold_set_event(env: &Env, contract: &Address, threshold: u32) {
101
101
  return false;
102
102
  }
103
103
  // Check data is a map with "threshold" field
104
- let data_map: Map<Symbol, u32> = event.2.try_into_val(env).unwrap();
104
+ let data_map: Map<Symbol, u32> = data.try_into_val(env).unwrap();
105
105
  data_map.get(Symbol::new(env, "threshold")) == Some(threshold)
106
106
  });
107
107
  assert!(found, "threshold_set event not found");
@@ -6,7 +6,7 @@ use crate::{
6
6
  self, Ownable, OwnableInitializer, OwnableStorage, OwnershipRenounced, OwnershipTransferred,
7
7
  OwnershipTransferring,
8
8
  },
9
- testing_utils::assert_event,
9
+ testing_utils::assert_eq_event,
10
10
  };
11
11
  use soroban_sdk::{
12
12
  contract, contractimpl,
@@ -137,7 +137,7 @@ fn transfer_ownership_with_event() {
137
137
  }]);
138
138
  client.transfer_ownership(&new_owner);
139
139
 
140
- assert_event(&env, &contract, OwnershipTransferred { old_owner: owner, new_owner: new_owner.clone() });
140
+ assert_eq_event(&env, &contract, OwnershipTransferred { old_owner: owner, new_owner: new_owner.clone() });
141
141
  assert_eq!(client.owner(), Some(new_owner));
142
142
  }
143
143
 
@@ -163,7 +163,7 @@ fn transfer_ownership_to_same_owner() {
163
163
  client.transfer_ownership(&owner);
164
164
 
165
165
  // Should still emit event and update (even if same owner)
166
- assert_event(&env, &contract, OwnershipTransferred { old_owner: owner.clone(), new_owner: owner.clone() });
166
+ assert_eq_event(&env, &contract, OwnershipTransferred { old_owner: owner.clone(), new_owner: owner.clone() });
167
167
  assert_eq!(client.owner(), Some(owner));
168
168
  }
169
169
 
@@ -270,7 +270,7 @@ fn propose_ownership_transfer_initiate_and_accept() {
270
270
  }]);
271
271
  client.propose_ownership_transfer(&new_owner, &ttl);
272
272
 
273
- assert_event(
273
+ assert_eq_event(
274
274
  &env,
275
275
  &contract,
276
276
  OwnershipTransferring { old_owner: owner.clone(), new_owner: new_owner.clone(), ttl },
@@ -290,7 +290,7 @@ fn propose_ownership_transfer_initiate_and_accept() {
290
290
  }]);
291
291
  client.accept_ownership();
292
292
 
293
- assert_event(&env, &contract, OwnershipTransferred { old_owner: owner, new_owner: new_owner.clone() });
293
+ assert_eq_event(&env, &contract, OwnershipTransferred { old_owner: owner, new_owner: new_owner.clone() });
294
294
  assert_eq!(client.owner(), Some(new_owner)); // Now new owner
295
295
  assert_eq!(client.pending_owner(), None);
296
296
  }
@@ -564,7 +564,7 @@ fn renounce_ownership_with_event() {
564
564
  }]);
565
565
  client.renounce_ownership();
566
566
 
567
- assert_event(&env, &contract, OwnershipRenounced { old_owner: owner });
567
+ assert_eq_event(&env, &contract, OwnershipRenounced { old_owner: owner });
568
568
  assert_eq!(client.owner(), None);
569
569
  }
570
570