@layerzerolabs/protocol-stellar-v2 0.2.20 → 0.2.22

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
@@ -0,0 +1,323 @@
1
+ //! Tests for the OApp Message Inspector feature.
2
+
3
+ use crate::tests::test_utils::{create_send_param, OFTTestSetup};
4
+ use common_macros::contract_error;
5
+ use endpoint_v2::MessagingFee;
6
+ use oapp::interfaces::IOAppMsgInspector;
7
+ use soroban_sdk::{
8
+ contract, contractimpl, panic_with_error,
9
+ testutils::{Address as _, MockAuth, MockAuthInvoke},
10
+ Address, Bytes, BytesN, Env, IntoVal,
11
+ };
12
+
13
+ // ==================== Mock Inspector Contracts ====================
14
+
15
+ /// A mock inspector that always passes (does nothing)
16
+ #[contract]
17
+ pub struct PassingInspector;
18
+
19
+ #[contractimpl]
20
+ impl IOAppMsgInspector for PassingInspector {
21
+ fn inspect(_env: &Env, _oapp: &Address, _message: &Bytes, _options: &Bytes) {
22
+ // Do nothing - inspection passes
23
+ }
24
+ }
25
+
26
+ #[contract_error]
27
+ pub enum InspectorError {
28
+ InspectionFailed = 1,
29
+ }
30
+
31
+ /// A mock inspector that always fails (panics)
32
+ #[contract]
33
+ pub struct FailingInspector;
34
+
35
+ #[contractimpl]
36
+ impl IOAppMsgInspector for FailingInspector {
37
+ fn inspect(env: &Env, _oapp: &Address, _message: &Bytes, _options: &Bytes) {
38
+ panic_with_error!(env, InspectorError::InspectionFailed);
39
+ }
40
+ }
41
+
42
+ // ==================== Storage Tests ====================
43
+
44
+ #[test]
45
+ fn test_msg_inspector_not_set_by_default() {
46
+ let env = Env::default();
47
+ let setup = OFTTestSetup::new(&env);
48
+
49
+ // msg_inspector should be None by default
50
+ let inspector = setup.oft.msg_inspector();
51
+ assert_eq!(inspector, None);
52
+ }
53
+
54
+ #[test]
55
+ fn test_set_msg_inspector() {
56
+ let env = Env::default();
57
+ let setup = OFTTestSetup::new(&env);
58
+
59
+ // Deploy a passing inspector
60
+ let inspector_address = env.register(PassingInspector, ());
61
+
62
+ // Owner sets the inspector
63
+ env.mock_auths(&[MockAuth {
64
+ address: &setup.owner,
65
+ invoke: &MockAuthInvoke {
66
+ contract: &setup.oft.address,
67
+ fn_name: "set_msg_inspector",
68
+ args: (&Some(inspector_address.clone()),).into_val(&env),
69
+ sub_invokes: &[],
70
+ },
71
+ }]);
72
+ setup.oft.set_msg_inspector(&Some(inspector_address.clone()));
73
+
74
+ // Verify inspector is set
75
+ let stored_inspector = setup.oft.msg_inspector();
76
+ assert_eq!(stored_inspector, Some(inspector_address));
77
+ }
78
+
79
+ #[test]
80
+ fn test_remove_msg_inspector() {
81
+ let env = Env::default();
82
+ let setup = OFTTestSetup::new(&env);
83
+
84
+ // Deploy and set a passing inspector first
85
+ let inspector_address = env.register(PassingInspector, ());
86
+
87
+ env.mock_auths(&[MockAuth {
88
+ address: &setup.owner,
89
+ invoke: &MockAuthInvoke {
90
+ contract: &setup.oft.address,
91
+ fn_name: "set_msg_inspector",
92
+ args: (&Some(inspector_address.clone()),).into_val(&env),
93
+ sub_invokes: &[],
94
+ },
95
+ }]);
96
+ setup.oft.set_msg_inspector(&Some(inspector_address));
97
+
98
+ // Verify it's set
99
+ assert!(setup.oft.msg_inspector().is_some());
100
+
101
+ // Remove the inspector by setting to None
102
+ env.mock_auths(&[MockAuth {
103
+ address: &setup.owner,
104
+ invoke: &MockAuthInvoke {
105
+ contract: &setup.oft.address,
106
+ fn_name: "set_msg_inspector",
107
+ args: (&None::<Address>,).into_val(&env),
108
+ sub_invokes: &[],
109
+ },
110
+ }]);
111
+ setup.oft.set_msg_inspector(&None);
112
+
113
+ // Verify inspector is removed
114
+ let stored_inspector = setup.oft.msg_inspector();
115
+ assert_eq!(stored_inspector, None);
116
+ }
117
+
118
+ // ==================== Access Control Tests ====================
119
+
120
+ #[test]
121
+ #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
122
+ fn test_set_msg_inspector_requires_owner() {
123
+ let env = Env::default();
124
+ let setup = OFTTestSetup::new(&env);
125
+
126
+ // Deploy a passing inspector
127
+ let inspector_address = env.register(PassingInspector, ());
128
+
129
+ // Non-owner tries to set the inspector (no mock_auth for owner)
130
+ let non_owner = Address::generate(&env);
131
+ env.mock_auths(&[MockAuth {
132
+ address: &non_owner,
133
+ invoke: &MockAuthInvoke {
134
+ contract: &setup.oft.address,
135
+ fn_name: "set_msg_inspector",
136
+ args: (&Some(inspector_address.clone()),).into_val(&env),
137
+ sub_invokes: &[],
138
+ },
139
+ }]);
140
+
141
+ // This should panic because non_owner is not the owner
142
+ setup.oft.set_msg_inspector(&Some(inspector_address));
143
+ }
144
+
145
+ // ==================== Integration Tests with Send ====================
146
+
147
+ #[test]
148
+ fn test_send_without_inspector_succeeds() {
149
+ let env = Env::default();
150
+ let setup = OFTTestSetup::new(&env);
151
+
152
+ let sender = Address::generate(&env);
153
+
154
+ // Set peer
155
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
156
+ let dst_eid = 100u32;
157
+ setup.set_peer(dst_eid, &peer);
158
+
159
+ let amount_ld = 12345670i128;
160
+ setup.fund_tokens(&sender, amount_ld);
161
+ setup.fund_native_fees(&sender, setup.native_fee);
162
+
163
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
164
+ let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
165
+ let oft_receipt = setup.quote_oft(&send_param);
166
+
167
+ // Send without inspector set - should succeed
168
+ let (msg_receipt, oft_receipt) = setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
169
+
170
+ assert!(msg_receipt.nonce > 0);
171
+ assert_eq!(oft_receipt.amount_sent_ld, amount_ld);
172
+ }
173
+
174
+ #[test]
175
+ fn test_send_with_passing_inspector() {
176
+ let env = Env::default();
177
+ let setup = OFTTestSetup::new(&env);
178
+
179
+ // Deploy and set a passing inspector
180
+ let inspector_address = env.register(PassingInspector, ());
181
+ env.mock_auths(&[MockAuth {
182
+ address: &setup.owner,
183
+ invoke: &MockAuthInvoke {
184
+ contract: &setup.oft.address,
185
+ fn_name: "set_msg_inspector",
186
+ args: (&Some(inspector_address.clone()),).into_val(&env),
187
+ sub_invokes: &[],
188
+ },
189
+ }]);
190
+ setup.oft.set_msg_inspector(&Some(inspector_address));
191
+
192
+ let sender = Address::generate(&env);
193
+
194
+ // Set peer
195
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
196
+ let dst_eid = 100u32;
197
+ setup.set_peer(dst_eid, &peer);
198
+
199
+ let amount_ld = 12345670i128;
200
+ setup.fund_tokens(&sender, amount_ld);
201
+ setup.fund_native_fees(&sender, setup.native_fee);
202
+
203
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
204
+ let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
205
+ let oft_receipt = setup.quote_oft(&send_param);
206
+
207
+ // Send with passing inspector - should succeed
208
+ let (msg_receipt, oft_receipt) = setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
209
+
210
+ assert!(msg_receipt.nonce > 0);
211
+ assert_eq!(oft_receipt.amount_sent_ld, amount_ld);
212
+ }
213
+
214
+ #[test]
215
+ fn test_send_with_failing_inspector() {
216
+ let env = Env::default();
217
+ let setup = OFTTestSetup::new(&env);
218
+
219
+ // Deploy and set a failing inspector
220
+ let inspector_address = env.register(FailingInspector, ());
221
+ env.mock_auths(&[MockAuth {
222
+ address: &setup.owner,
223
+ invoke: &MockAuthInvoke {
224
+ contract: &setup.oft.address,
225
+ fn_name: "set_msg_inspector",
226
+ args: (&Some(inspector_address.clone()),).into_val(&env),
227
+ sub_invokes: &[],
228
+ },
229
+ }]);
230
+ setup.oft.set_msg_inspector(&Some(inspector_address));
231
+
232
+ let sender = Address::generate(&env);
233
+
234
+ // Set peer
235
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
236
+ let dst_eid = 100u32;
237
+ setup.set_peer(dst_eid, &peer);
238
+
239
+ let amount_ld = 12345670i128;
240
+ setup.fund_tokens(&sender, amount_ld);
241
+ setup.fund_native_fees(&sender, setup.native_fee);
242
+
243
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
244
+ let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
245
+ let oft_receipt = setup.quote_oft(&send_param);
246
+
247
+ // Send with failing inspector - should fail
248
+ let result = setup.try_send(&sender, &send_param, &fee, &sender, &oft_receipt);
249
+
250
+ // Verify the send failed due to inspector
251
+ assert!(result.is_err() || result.unwrap().is_err());
252
+ }
253
+
254
+ // ==================== Integration Tests with Quote ====================
255
+
256
+ #[test]
257
+ fn test_quote_send_with_passing_inspector() {
258
+ let env = Env::default();
259
+ let setup = OFTTestSetup::new(&env);
260
+
261
+ // Deploy and set a passing inspector
262
+ let inspector_address = env.register(PassingInspector, ());
263
+ env.mock_auths(&[MockAuth {
264
+ address: &setup.owner,
265
+ invoke: &MockAuthInvoke {
266
+ contract: &setup.oft.address,
267
+ fn_name: "set_msg_inspector",
268
+ args: (&Some(inspector_address.clone()),).into_val(&env),
269
+ sub_invokes: &[],
270
+ },
271
+ }]);
272
+ setup.oft.set_msg_inspector(&Some(inspector_address));
273
+
274
+ let sender = Address::generate(&env);
275
+
276
+ // Set peer
277
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
278
+ let dst_eid = 100u32;
279
+ setup.set_peer(dst_eid, &peer);
280
+
281
+ let amount_ld = 12345670i128;
282
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
283
+
284
+ // Quote with passing inspector - should succeed
285
+ let fee = setup.oft.quote_send(&sender, &send_param, &false);
286
+
287
+ assert!(fee.native_fee > 0);
288
+ }
289
+
290
+ #[test]
291
+ fn test_quote_send_with_failing_inspector() {
292
+ let env = Env::default();
293
+ let setup = OFTTestSetup::new(&env);
294
+
295
+ // Deploy and set a failing inspector
296
+ let inspector_address = env.register(FailingInspector, ());
297
+ env.mock_auths(&[MockAuth {
298
+ address: &setup.owner,
299
+ invoke: &MockAuthInvoke {
300
+ contract: &setup.oft.address,
301
+ fn_name: "set_msg_inspector",
302
+ args: (&Some(inspector_address.clone()),).into_val(&env),
303
+ sub_invokes: &[],
304
+ },
305
+ }]);
306
+ setup.oft.set_msg_inspector(&Some(inspector_address));
307
+
308
+ let sender = Address::generate(&env);
309
+
310
+ // Set peer
311
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
312
+ let dst_eid = 100u32;
313
+ setup.set_peer(dst_eid, &peer);
314
+
315
+ let amount_ld = 12345670i128;
316
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
317
+
318
+ // Quote with failing inspector - should fail
319
+ let result = setup.oft.try_quote_send(&sender, &send_param, &false);
320
+
321
+ // Verify the quote failed due to inspector
322
+ assert!(result.is_err());
323
+ }
@@ -11,7 +11,7 @@ use soroban_sdk::{
11
11
  testutils::{Address as _, MockAuth, MockAuthInvoke},
12
12
  Address, Bytes, BytesN, Env, IntoVal,
13
13
  };
14
- use utils::testing_utils::assert_event;
14
+ use utils::testing_utils::assert_contains_event;
15
15
 
16
16
  use super::test_utils::{create_send_param, OFTTestSetup};
17
17
 
@@ -349,7 +349,7 @@ fn test_send_emits_oft_sent_event() {
349
349
  let (msg_receipt, oft_receipt) = setup.send(&sender, &send_param, &fee, &sender, &quoted_receipt);
350
350
 
351
351
  // Assert OFTSent event was emitted with correct values
352
- assert_event(
352
+ assert_contains_event(
353
353
  &env,
354
354
  &setup.oft.address,
355
355
  OFTSent {
@@ -16,8 +16,6 @@ use soroban_sdk::{
16
16
  token::{StellarAssetClient, TokenClient},
17
17
  Address, Bytes, BytesN, Env, IntoVal, String, Symbol,
18
18
  };
19
- use stellar_macros::default_impl;
20
- use stellar_tokens::fungible::{Base, FungibleToken};
21
19
 
22
20
  // ==================== Constants ====================
23
21
 
@@ -106,7 +104,7 @@ pub fn create_origin(src_eid: u32, sender: &BytesN<32>, nonce: u64) -> Origin {
106
104
  mod test_mint_burn_oft {
107
105
  use crate::{
108
106
  self as oft_core,
109
- oft_core::{lz_receive, OFTCore, OFTInternal},
107
+ oft_core::{OFTCore, OFTInternal},
110
108
  types::OFTReceipt,
111
109
  };
112
110
  use endpoint_v2::Origin;
@@ -150,7 +148,7 @@ mod test_mint_burn_oft {
150
148
  executor: &Address,
151
149
  value: i128,
152
150
  ) {
153
- lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
151
+ <Self as OFTInternal>::__receive(env, origin, guid, message, extra_data, executor, value)
154
152
  }
155
153
  }
156
154
 
@@ -174,7 +172,7 @@ pub use test_mint_burn_oft::TestMintBurnOFT;
174
172
  mod test_lock_unlock_oft {
175
173
  use crate::{
176
174
  self as oft_core,
177
- oft_core::{lz_receive, OFTCore, OFTInternal},
175
+ oft_core::{OFTCore, OFTInternal},
178
176
  types::OFTReceipt,
179
177
  };
180
178
  use endpoint_v2::Origin;
@@ -211,7 +209,7 @@ mod test_lock_unlock_oft {
211
209
  executor: &Address,
212
210
  value: i128,
213
211
  ) {
214
- lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
212
+ <Self as OFTInternal>::__receive(env, origin, guid, message, extra_data, executor, value)
215
213
  }
216
214
  }
217
215
 
@@ -251,6 +249,7 @@ impl DummyRecipient {
251
249
  pub fn __constructor(_env: &Env) {}
252
250
  }
253
251
 
252
+ /// Simple token contract for testing (replaces OpenZeppelin dependency)
254
253
  #[contract]
255
254
  pub struct DummyToken;
256
255
 
@@ -260,9 +259,19 @@ impl DummyToken {
260
259
  env.storage().instance().get(&symbol_short!("admin")).unwrap()
261
260
  }
262
261
 
262
+ fn get_balance(env: &Env, addr: &Address) -> i128 {
263
+ env.storage().persistent().get(&addr).unwrap_or(0)
264
+ }
265
+
266
+ fn set_balance(env: &Env, addr: &Address, amount: i128) {
267
+ env.storage().persistent().set(&addr, &amount);
268
+ }
269
+
263
270
  pub fn __constructor(env: &Env, owner: Address, decimals: u32) {
264
- Base::set_metadata(env, decimals, String::from_str(env, "DummyToken"), String::from_str(env, "DUMMY"));
265
271
  env.storage().instance().set(&symbol_short!("admin"), &owner);
272
+ env.storage().instance().set(&symbol_short!("decimal"), &decimals);
273
+ env.storage().instance().set(&symbol_short!("name"), &String::from_str(env, "DummyToken"));
274
+ env.storage().instance().set(&symbol_short!("symbol"), &String::from_str(env, "DUMMY"));
266
275
  }
267
276
 
268
277
  // keep the same behavior as SAC that requires admin's authorization
@@ -273,21 +282,57 @@ impl DummyToken {
273
282
 
274
283
  pub fn mint(env: &Env, to: &Address, amount: i128) {
275
284
  Self::admin(env).require_auth();
276
- Base::mint(env, &to, amount);
285
+ if amount < 0 {
286
+ panic!("negative amount");
287
+ }
288
+ let balance = Self::get_balance(env, to);
289
+ Self::set_balance(env, to, balance + amount);
277
290
  log!(&env, "minted {} to {}", amount, to);
278
291
  }
279
292
 
280
293
  // keep the same behavior as SAC that requires from's authorization
281
294
  pub fn burn(env: &Env, from: &Address, amount: i128) {
282
- Base::burn(env, &from, amount);
295
+ from.require_auth();
296
+ if amount < 0 {
297
+ panic!("negative amount");
298
+ }
299
+ let balance = Self::get_balance(env, from);
300
+ if balance < amount {
301
+ panic!("insufficient balance");
302
+ }
303
+ Self::set_balance(env, from, balance - amount);
283
304
  log!(&env, "burned {} from {}", amount, from);
284
305
  }
285
- }
286
306
 
287
- #[default_impl]
288
- #[contractimpl]
289
- impl FungibleToken for DummyToken {
290
- type ContractType = Base;
307
+ pub fn balance(env: &Env, id: Address) -> i128 {
308
+ Self::get_balance(env, &id)
309
+ }
310
+
311
+ pub fn transfer(env: &Env, from: Address, to: Address, amount: i128) {
312
+ from.require_auth();
313
+ if amount < 0 {
314
+ panic!("negative amount");
315
+ }
316
+ let from_balance = Self::get_balance(env, &from);
317
+ if from_balance < amount {
318
+ panic!("insufficient balance");
319
+ }
320
+ Self::set_balance(env, &from, from_balance - amount);
321
+ let to_balance = Self::get_balance(env, &to);
322
+ Self::set_balance(env, &to, to_balance + amount);
323
+ }
324
+
325
+ pub fn decimals(env: &Env) -> u32 {
326
+ env.storage().instance().get(&symbol_short!("decimal")).unwrap_or(7)
327
+ }
328
+
329
+ pub fn name(env: &Env) -> String {
330
+ env.storage().instance().get(&symbol_short!("name")).unwrap()
331
+ }
332
+
333
+ pub fn symbol(env: &Env) -> String {
334
+ env.storage().instance().get(&symbol_short!("symbol")).unwrap()
335
+ }
291
336
  }
292
337
 
293
338
  // ==================== Mock Endpoint ====================
@@ -18,4 +18,3 @@ common-macros = { workspace = true }
18
18
 
19
19
  [dev-dependencies]
20
20
  soroban-sdk = { workspace = true, features = ["testutils"] }
21
- stellar-strkey = "0.0.14"
@@ -1,7 +1,7 @@
1
1
  use common_macros::contract_error;
2
2
 
3
3
  // Utils library error codes: 1000-1099
4
- // See ERROR_SPEC.md for allocation rules
4
+ // See docs/error-spec.md for allocation rules
5
5
 
6
6
  /// BufferReaderError: 1000-1009
7
7
  #[contract_error]
@@ -58,7 +58,7 @@ pub trait Multisig: Auth {
58
58
  // ===========================================================================
59
59
 
60
60
  /// Adds or removes a signer from the multisig. Requires owner authorization.
61
- fn set_signer(env: &Env, signer: &BytesN<20>, active: bool) {
61
+ fn set_signer(env: &soroban_sdk::Env, signer: &soroban_sdk::BytesN<20>, active: bool) {
62
62
  auth::require_auth::<Self>(env);
63
63
  match active {
64
64
  true => add_signer(env, signer),
@@ -67,7 +67,7 @@ pub trait Multisig: Auth {
67
67
  }
68
68
 
69
69
  /// Sets the signature threshold (quorum). Requires owner authorization.
70
- fn set_threshold(env: &Env, threshold: u32) {
70
+ fn set_threshold(env: &soroban_sdk::Env, threshold: u32) {
71
71
  auth::require_auth::<Self>(env);
72
72
  set_threshold(env, threshold);
73
73
  }
@@ -77,22 +77,22 @@ pub trait Multisig: Auth {
77
77
  // ===========================================================================
78
78
 
79
79
  /// Returns all registered signers.
80
- fn get_signers(env: &Env) -> Vec<BytesN<20>> {
80
+ fn get_signers(env: &soroban_sdk::Env) -> soroban_sdk::Vec<soroban_sdk::BytesN<20>> {
81
81
  MultisigStorage::signers(env)
82
82
  }
83
83
 
84
84
  /// Returns the total number of registered signers.
85
- fn total_signers(env: &Env) -> u32 {
85
+ fn total_signers(env: &soroban_sdk::Env) -> u32 {
86
86
  MultisigStorage::signers(env).len()
87
87
  }
88
88
 
89
89
  /// Checks if an address is a registered signer.
90
- fn is_signer(env: &Env, signer: &BytesN<20>) -> bool {
90
+ fn is_signer(env: &soroban_sdk::Env, signer: &soroban_sdk::BytesN<20>) -> bool {
91
91
  MultisigStorage::signers(env).iter().any(|s| &s == signer)
92
92
  }
93
93
 
94
94
  /// Returns the current signature threshold (quorum).
95
- fn threshold(env: &Env) -> u32 {
95
+ fn threshold(env: &soroban_sdk::Env) -> u32 {
96
96
  MultisigStorage::threshold(env)
97
97
  }
98
98
 
@@ -101,12 +101,21 @@ pub trait Multisig: Auth {
101
101
  // ===========================================================================
102
102
 
103
103
  /// Verifies signatures against the configured threshold.
104
- fn verify_signatures(env: &Env, digest: &BytesN<32>, signatures: &Vec<BytesN<65>>) {
104
+ fn verify_signatures(
105
+ env: &soroban_sdk::Env,
106
+ digest: &soroban_sdk::BytesN<32>,
107
+ signatures: &soroban_sdk::Vec<soroban_sdk::BytesN<65>>,
108
+ ) {
105
109
  Self::verify_n_signatures(env, digest, signatures, MultisigStorage::threshold(env));
106
110
  }
107
111
 
108
112
  /// Verifies signatures against a custom threshold.
109
- fn verify_n_signatures(env: &Env, digest: &BytesN<32>, signatures: &Vec<BytesN<65>>, threshold: u32) {
113
+ fn verify_n_signatures(
114
+ env: &soroban_sdk::Env,
115
+ digest: &soroban_sdk::BytesN<32>,
116
+ signatures: &soroban_sdk::Vec<soroban_sdk::BytesN<65>>,
117
+ threshold: u32,
118
+ ) {
110
119
  assert_with_error!(env, threshold > 0, MultisigError::ZeroThreshold);
111
120
  assert_with_error!(env, signatures.len() >= threshold, MultisigError::SignatureError);
112
121
 
@@ -64,12 +64,12 @@ pub trait Ownable: Sized + Auth {
64
64
  // ===========================================================================
65
65
 
66
66
  /// Returns the current owner address, or None if no owner is set.
67
- fn owner(env: &Env) -> Option<Address> {
67
+ fn owner(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
68
68
  OwnableStorage::owner(env)
69
69
  }
70
70
 
71
71
  /// Returns the pending owner address for 2-step transfer, or None if no transfer is pending.
72
- fn pending_owner(env: &Env) -> Option<Address> {
72
+ fn pending_owner(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
73
73
  OwnableStorage::pending_owner(env)
74
74
  }
75
75
 
@@ -85,7 +85,7 @@ pub trait Ownable: Sized + Auth {
85
85
  /// # Panics
86
86
  /// - `OwnerNotSet` if no owner is currently set
87
87
  /// - `TransferInProgress` if a 2-step transfer is in progress
88
- fn transfer_ownership(env: &Env, new_owner: &Address) {
88
+ fn transfer_ownership(env: &soroban_sdk::Env, new_owner: &soroban_sdk::Address) {
89
89
  let old_owner = enforce_owner_auth::<Self>(env);
90
90
  assert_no_pending_transfer::<Self>(env);
91
91
 
@@ -112,7 +112,7 @@ pub trait Ownable: Sized + Auth {
112
112
  /// - `NoPendingTransfer` when cancelling and no pending transfer exists
113
113
  /// - `InvalidTtl` if ttl exceeds max TTL
114
114
  /// - `InvalidPendingOwner` when cancelling with wrong new_owner address
115
- fn propose_ownership_transfer(env: &Env, new_owner: &Address, ttl: u32) {
115
+ fn propose_ownership_transfer(env: &soroban_sdk::Env, new_owner: &soroban_sdk::Address, ttl: u32) {
116
116
  let old_owner = enforce_owner_auth::<Self>(env);
117
117
 
118
118
  // Cancel case: ttl == 0
@@ -142,7 +142,7 @@ pub trait Ownable: Sized + Auth {
142
142
  ///
143
143
  /// # Panics
144
144
  /// - `NoPendingTransfer` if there is no pending transfer (or it expired)
145
- fn accept_ownership(env: &Env) {
145
+ fn accept_ownership(env: &soroban_sdk::Env) {
146
146
  let new_owner = Self::pending_owner(env).unwrap_or_panic(env, OwnableError::NoPendingTransfer);
147
147
 
148
148
  // Require authorization from the pending owner
@@ -169,7 +169,7 @@ pub trait Ownable: Sized + Auth {
169
169
  /// # Panics
170
170
  /// - `OwnerNotSet` if no owner is currently set
171
171
  /// - `TransferInProgress` if a 2-step transfer is in progress (cancel it first)
172
- fn renounce_ownership(env: &Env) {
172
+ fn renounce_ownership(env: &soroban_sdk::Env) {
173
173
  let old_owner = enforce_owner_auth::<Self>(env);
174
174
  assert_no_pending_transfer::<Self>(env);
175
175