@layerzerolabs/protocol-stellar-v2 0.2.19 → 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 (249) hide show
  1. package/.turbo/turbo-build.log +795 -791
  2. package/.turbo/turbo-lint.log +325 -155
  3. package/.turbo/turbo-test.log +1398 -1277
  4. package/Cargo.lock +122 -111
  5. package/Cargo.toml +32 -16
  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 +18 -7
  9. package/contracts/common-macros/src/lib.rs +31 -14
  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/contract_ttl.rs +1 -1
  13. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +6 -12
  14. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +12 -17
  15. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
  16. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +2 -7
  17. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +20 -14
  18. package/contracts/common-macros/src/tests/upgradeable.rs +26 -4
  19. package/contracts/common-macros/src/ttl_configurable.rs +2 -10
  20. package/contracts/common-macros/src/ttl_extendable.rs +2 -10
  21. package/contracts/common-macros/src/upgradeable.rs +61 -26
  22. package/contracts/common-macros/src/utils.rs +0 -9
  23. package/contracts/endpoint-v2/src/lib.rs +3 -2
  24. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +2 -2
  25. package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +3 -3
  26. package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +4 -4
  27. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +17 -5
  28. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
  29. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +2 -2
  30. package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +2 -2
  31. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +6 -6
  32. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +67 -37
  33. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +5 -5
  34. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +44 -54
  35. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +7 -7
  36. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +8 -8
  37. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +3 -3
  38. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +4 -4
  39. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +3 -3
  40. package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +2 -2
  41. package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +3 -3
  42. package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +2 -2
  43. package/contracts/layerzero-views/Cargo.toml +0 -1
  44. package/contracts/layerzero-views/src/layerzero_view.rs +1 -13
  45. package/contracts/macro-integration-tests/Cargo.toml +5 -15
  46. package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +48 -0
  47. package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +170 -0
  48. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +154 -0
  49. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +338 -0
  50. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +435 -0
  51. package/contracts/macro-integration-tests/tests/runtime.rs +1 -0
  52. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.rs +8 -0
  53. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -0
  54. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.rs +8 -0
  55. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.stderr +71 -0
  56. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.rs +10 -0
  57. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +5 -0
  58. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.rs +8 -0
  59. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -0
  60. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.rs +8 -0
  61. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -0
  62. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +38 -0
  63. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +96 -0
  64. package/contracts/macro-integration-tests/tests/ui/oapp/pass/minimal_contract.rs +64 -0
  65. package/contracts/macro-integration-tests/tests/ui/oapp/pass/struct_with_fields.rs +46 -0
  66. package/contracts/macro-integration-tests/tests/ui/ownable/fail/only_auth_missing_env.stderr +8 -0
  67. package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +1 -1
  68. package/contracts/macro-integration-tests/tests/ui/ownable/pass/only_auth_env_param_variants.rs +1 -1
  69. package/contracts/macro-integration-tests/tests/ui_oapp.rs +11 -0
  70. package/contracts/message-libs/message-lib-common/Cargo.toml +0 -1
  71. package/contracts/message-libs/message-lib-common/src/errors.rs +1 -1
  72. package/contracts/message-libs/treasury/Cargo.toml +0 -2
  73. package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +2 -2
  74. package/contracts/message-libs/uln-302/src/events.rs +4 -0
  75. package/contracts/message-libs/uln-302/src/send_uln.rs +22 -6
  76. package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +2 -2
  77. package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +2 -2
  78. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +2 -2
  79. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +2 -2
  80. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +2 -2
  81. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +21 -67
  82. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +2 -2
  83. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +2 -2
  84. package/contracts/oapps/counter/Cargo.toml +5 -6
  85. package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
  86. package/contracts/oapps/counter/integration_tests/utils.rs +19 -12
  87. package/contracts/oapps/oapp/src/errors.rs +1 -1
  88. package/contracts/oapps/oapp/src/interfaces/mod.rs +3 -0
  89. package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +47 -0
  90. package/contracts/oapps/oapp/src/lib.rs +1 -0
  91. package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +4 -4
  92. package/contracts/oapps/oapp/src/oapp_core.rs +5 -5
  93. package/contracts/oapps/oapp/src/oapp_options_type3.rs +12 -4
  94. package/contracts/oapps/oapp/src/oapp_receiver.rs +14 -9
  95. package/contracts/oapps/oapp/src/tests/mod.rs +4 -4
  96. package/contracts/oapps/oapp/src/tests/oapp_core.rs +223 -0
  97. package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +240 -0
  98. package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +381 -0
  99. package/contracts/oapps/oapp/src/tests/oapp_sender.rs +569 -0
  100. package/contracts/oapps/oapp-macros/Cargo.toml +8 -4
  101. package/contracts/oapps/oapp-macros/src/generators.rs +9 -34
  102. package/contracts/oapps/oapp-macros/src/lib.rs +3 -0
  103. package/contracts/oapps/oapp-macros/src/tests/mod.rs +2 -0
  104. package/contracts/oapps/oapp-macros/src/tests/oapp.rs +88 -0
  105. package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +86 -0
  106. package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +103 -0
  107. package/contracts/oapps/oft/integration-tests/utils.rs +28 -8
  108. package/contracts/oapps/oft/src/extensions/oft_fee.rs +153 -75
  109. package/contracts/oapps/oft/src/extensions/pausable.rs +61 -12
  110. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +198 -134
  111. package/contracts/oapps/oft/src/oft.rs +45 -50
  112. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +1 -1
  113. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +4 -26
  114. package/contracts/oapps/oft-core/Cargo.toml +1 -4
  115. package/contracts/oapps/oft-core/integration-tests/setup.rs +3 -3
  116. package/contracts/oapps/oft-core/integration-tests/utils.rs +21 -3
  117. package/contracts/oapps/oft-core/src/errors.rs +3 -2
  118. package/contracts/oapps/oft-core/src/events.rs +6 -0
  119. package/contracts/oapps/oft-core/src/lib.rs +1 -1
  120. package/contracts/oapps/oft-core/src/oft_core.rs +341 -246
  121. package/contracts/oapps/oft-core/src/storage.rs +7 -3
  122. package/contracts/oapps/oft-core/src/tests/mod.rs +1 -0
  123. package/contracts/oapps/oft-core/src/tests/test_decimals.rs +37 -2
  124. package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +2 -2
  125. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +323 -0
  126. package/contracts/oapps/oft-core/src/tests/test_send.rs +2 -2
  127. package/contracts/oapps/oft-core/src/tests/test_utils.rs +61 -16
  128. package/contracts/upgrader/src/lib.rs +30 -57
  129. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
  130. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
  131. package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
  132. package/contracts/utils/Cargo.toml +0 -1
  133. package/contracts/utils/src/buffer_reader.rs +1 -0
  134. package/contracts/utils/src/errors.rs +4 -2
  135. package/contracts/utils/src/multisig.rs +17 -8
  136. package/contracts/utils/src/ownable.rs +6 -6
  137. package/contracts/utils/src/testing_utils.rs +124 -54
  138. package/contracts/utils/src/tests/multisig.rs +12 -12
  139. package/contracts/utils/src/tests/ownable.rs +6 -6
  140. package/contracts/utils/src/tests/testing_utils.rs +50 -167
  141. package/contracts/utils/src/tests/ttl_configurable.rs +5 -5
  142. package/contracts/utils/src/tests/upgradeable.rs +372 -175
  143. package/contracts/utils/src/ttl_configurable.rs +13 -7
  144. package/contracts/utils/src/upgradeable.rs +48 -23
  145. package/contracts/workers/dvn/Cargo.toml +6 -6
  146. package/contracts/workers/dvn/src/auth.rs +12 -42
  147. package/contracts/workers/dvn/src/dvn.rs +15 -40
  148. package/contracts/workers/dvn/src/errors.rs +0 -1
  149. package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
  150. package/contracts/workers/dvn/src/lib.rs +4 -3
  151. package/contracts/workers/dvn/src/tests/auth.rs +1 -1
  152. package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
  153. package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
  154. package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
  155. package/contracts/workers/dvn/src/tests/setup.rs +5 -9
  156. package/contracts/workers/dvn-fee-lib/Cargo.toml +2 -2
  157. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +38 -22
  158. package/contracts/workers/dvn-fee-lib/src/lib.rs +12 -2
  159. package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +17 -16
  160. package/contracts/workers/executor/Cargo.toml +4 -0
  161. package/contracts/workers/executor/src/executor.rs +15 -36
  162. package/contracts/workers/executor/src/lib.rs +2 -2
  163. package/contracts/workers/executor/src/tests/auth.rs +394 -0
  164. package/contracts/workers/executor/src/tests/executor.rs +410 -0
  165. package/contracts/workers/executor/src/tests/mod.rs +3 -0
  166. package/contracts/workers/executor/src/tests/setup.rs +250 -0
  167. package/contracts/workers/executor-fee-lib/Cargo.toml +7 -1
  168. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +62 -15
  169. package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
  170. package/contracts/workers/executor-fee-lib/src/lib.rs +11 -2
  171. package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
  172. package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
  173. package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
  174. package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
  175. package/contracts/workers/executor-helper/Cargo.toml +0 -1
  176. package/contracts/workers/executor-helper/src/lib.rs +3 -0
  177. package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
  178. package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
  179. package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
  180. package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
  181. package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
  182. package/contracts/workers/price-feed/Cargo.toml +7 -1
  183. package/contracts/workers/price-feed/src/events.rs +1 -1
  184. package/contracts/workers/price-feed/src/lib.rs +12 -4
  185. package/contracts/workers/price-feed/src/price_feed.rs +5 -21
  186. package/contracts/workers/price-feed/src/storage.rs +1 -1
  187. package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
  188. package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
  189. package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
  190. package/contracts/workers/price-feed/src/types.rs +1 -1
  191. package/contracts/workers/worker/src/errors.rs +1 -4
  192. package/contracts/workers/worker/src/lib.rs +0 -2
  193. package/contracts/workers/worker/src/storage.rs +32 -29
  194. package/contracts/workers/worker/src/tests/setup.rs +2 -8
  195. package/contracts/workers/worker/src/tests/worker.rs +96 -74
  196. package/contracts/workers/worker/src/worker.rs +75 -75
  197. package/docs/error-spec.md +55 -0
  198. package/docs/layerzero-v2-on-stellar.md +447 -0
  199. package/docs/oapp-guide.md +212 -0
  200. package/docs/oft-guide.md +314 -0
  201. package/package.json +3 -3
  202. package/sdk/.turbo/turbo-test.log +268 -263
  203. package/sdk/dist/generated/bml.d.ts +12 -4
  204. package/sdk/dist/generated/bml.js +9 -7
  205. package/sdk/dist/generated/counter.d.ts +306 -298
  206. package/sdk/dist/generated/counter.js +48 -46
  207. package/sdk/dist/generated/dvn.d.ts +450 -411
  208. package/sdk/dist/generated/dvn.js +66 -64
  209. package/sdk/dist/generated/dvn_fee_lib.d.ts +294 -338
  210. package/sdk/dist/generated/dvn_fee_lib.js +33 -64
  211. package/sdk/dist/generated/endpoint.d.ts +108 -100
  212. package/sdk/dist/generated/endpoint.js +21 -19
  213. package/sdk/dist/generated/executor.d.ts +414 -370
  214. package/sdk/dist/generated/executor.js +58 -55
  215. package/sdk/dist/generated/executor_fee_lib.d.ts +333 -377
  216. package/sdk/dist/generated/executor_fee_lib.js +34 -65
  217. package/sdk/dist/generated/executor_helper.d.ts +26 -190
  218. package/sdk/dist/generated/executor_helper.js +23 -28
  219. package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
  220. package/sdk/dist/generated/layerzero_view.js +294 -0
  221. package/sdk/dist/generated/oft.d.ts +408 -385
  222. package/sdk/dist/generated/oft.js +89 -92
  223. package/sdk/dist/generated/price_feed.d.ts +385 -429
  224. package/sdk/dist/generated/price_feed.js +50 -81
  225. package/sdk/dist/generated/sml.d.ts +108 -100
  226. package/sdk/dist/generated/sml.js +21 -19
  227. package/sdk/dist/generated/treasury.d.ts +108 -100
  228. package/sdk/dist/generated/treasury.js +21 -19
  229. package/sdk/dist/generated/uln302.d.ts +108 -100
  230. package/sdk/dist/generated/uln302.js +23 -21
  231. package/sdk/dist/generated/upgrader.d.ts +189 -18
  232. package/sdk/dist/generated/upgrader.js +84 -4
  233. package/sdk/dist/index.d.ts +1 -0
  234. package/sdk/dist/index.js +2 -0
  235. package/sdk/package.json +1 -1
  236. package/sdk/src/index.ts +3 -0
  237. package/sdk/test/oft-sml.test.ts +4 -4
  238. package/sdk/test/suites/localnet.ts +84 -20
  239. package/sdk/test/upgrader.test.ts +2 -3
  240. package/tools/ts-bindings-gen/src/main.rs +2 -1
  241. package/contracts/ERROR_SPEC.md +0 -44
  242. package/contracts/endpoint-v2/ARCHITECTURE.md +0 -233
  243. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +0 -175
  244. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +0 -212
  245. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +0 -153
  246. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +0 -294
  247. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
  248. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
  249. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
@@ -3,11 +3,15 @@ use soroban_sdk::Address;
3
3
 
4
4
  #[storage]
5
5
  pub enum OFTStorage {
6
- /// The decimal conversion rate used for cross-chain normalization
7
- #[instance(i128)]
8
- DecimalConversionRate,
6
+ /// The difference between local and shared decimals (local_decimals - shared_decimals)
7
+ #[instance(u32)]
8
+ DecimalsDiff,
9
9
 
10
10
  /// The address of the underlying token contract
11
11
  #[instance(Address)]
12
12
  Token,
13
+
14
+ /// The optional message inspector contract address
15
+ #[instance(Address)]
16
+ MsgInspector,
13
17
  }
@@ -5,6 +5,7 @@ pub mod test_oft_msg_codec;
5
5
 
6
6
  pub mod test_decimals;
7
7
  pub mod test_lz_receive;
8
+ pub mod test_msg_inspector;
8
9
  pub mod test_oft_version;
9
10
  pub mod test_quote_oft;
10
11
  pub mod test_quote_send;
@@ -17,7 +17,7 @@ fn test_decimal_conversion_rate() {
17
17
  }
18
18
 
19
19
  #[test]
20
- #[should_panic(expected = "Error(Contract, #3000)")] // InvalidLocalDecimals
20
+ #[should_panic(expected = "Error(Contract, #3001)")] // InvalidLocalDecimals
21
21
  fn test_invalid_local_decimals() {
22
22
  let env = Env::default();
23
23
  OFTTestSetupBuilder::new(&env).with_token_decimals(5).with_shared_decimals(6).build();
@@ -34,7 +34,7 @@ fn test_to_ld_overflow() {
34
34
  }
35
35
 
36
36
  #[test]
37
- #[should_panic(expected = "Error(Contract, #3002)")] // Overflow
37
+ #[should_panic(expected = "Error(Contract, #3003)")] // Overflow
38
38
  fn test_to_sd_overflow() {
39
39
  let env = Env::default();
40
40
 
@@ -87,3 +87,38 @@ fn test_to_sd_truncates_dust() {
87
87
  // 20 LD → 2 SD (exact)
88
88
  assert_eq!(to_sd(&env, 20, conversion_rate), 2);
89
89
  }
90
+
91
+ // ==================== Shared Decimals Tests ====================
92
+
93
+ #[test]
94
+ fn test_shared_decimals_default() {
95
+ let env = Env::default();
96
+ let setup = OFTTestSetup::new(&env);
97
+
98
+ // Default setup: 7 local decimals, 6 shared decimals
99
+ let shared = setup.oft.shared_decimals();
100
+ assert_eq!(shared, setup.shared_decimals);
101
+ assert_eq!(shared, 6);
102
+ }
103
+
104
+ #[test]
105
+ fn test_shared_decimals_equal_to_local() {
106
+ let env = Env::default();
107
+ // When shared_decimals == local_decimals, conversion_rate = 1
108
+ let setup = OFTTestSetupBuilder::new(&env).with_token_decimals(8).with_shared_decimals(8).build();
109
+
110
+ let shared = setup.oft.shared_decimals();
111
+ assert_eq!(shared, 8);
112
+ assert_eq!(setup.oft.decimal_conversion_rate(), 1);
113
+ }
114
+
115
+ #[test]
116
+ fn test_shared_decimals_large_difference() {
117
+ let env = Env::default();
118
+ // 18 local decimals, 6 shared decimals → conversion_rate = 10^12
119
+ let setup = OFTTestSetupBuilder::new(&env).with_token_decimals(18).with_shared_decimals(6).build();
120
+
121
+ let shared = setup.oft.shared_decimals();
122
+ assert_eq!(shared, 6);
123
+ assert_eq!(setup.oft.decimal_conversion_rate(), 10_i128.pow(12));
124
+ }
@@ -9,7 +9,7 @@ use crate::{
9
9
  };
10
10
  use endpoint_v2::LayerZeroReceiverClient;
11
11
  use soroban_sdk::{testutils::Address as _, Address, Bytes, BytesN, Env};
12
- use utils::testing_utils::assert_event;
12
+ use utils::testing_utils::assert_contains_event;
13
13
 
14
14
  // Helper function to reduce code duplication for lz_receive tests
15
15
  fn run_lz_receive_test(setup: &OFTTestSetup, recipient: &Address, amount_sd: u64) {
@@ -37,7 +37,7 @@ fn run_lz_receive_test(setup: &OFTTestSetup, recipient: &Address, amount_sd: u64
37
37
  let conversion_rate = setup.oft.decimal_conversion_rate();
38
38
  let expected_amount_ld = (amount_sd as i128) * conversion_rate;
39
39
  setup.lz_receive(&executor, &origin, &guid, &message, &extra_data, 0);
40
- assert_event(
40
+ assert_contains_event(
41
41
  env,
42
42
  &setup.oft.address,
43
43
  OFTReceived { guid: guid.clone(), src_eid, to: recipient.clone(), amount_received_ld: expected_amount_ld },
@@ -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::{initialize_oft, lz_receive, OFTCore, OFTInternal},
107
+ oft_core::{OFTCore, OFTInternal},
110
108
  types::OFTReceipt,
111
109
  };
112
110
  use endpoint_v2::Origin;
@@ -133,7 +131,7 @@ mod test_mint_burn_oft {
133
131
  delegate: &Option<Address>,
134
132
  shared_decimals: u32,
135
133
  ) {
136
- initialize_oft::<Self>(env, owner, token, endpoint, delegate, shared_decimals)
134
+ Self::__initialize_oft(env, owner, token, endpoint, delegate, shared_decimals)
137
135
  }
138
136
  }
139
137
 
@@ -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::{initialize_oft, lz_receive, OFTCore, OFTInternal},
175
+ oft_core::{OFTCore, OFTInternal},
178
176
  types::OFTReceipt,
179
177
  };
180
178
  use endpoint_v2::Origin;
@@ -194,7 +192,7 @@ mod test_lock_unlock_oft {
194
192
  delegate: &Option<Address>,
195
193
  shared_decimals: u32,
196
194
  ) {
197
- initialize_oft::<Self>(env, owner, token, endpoint, delegate, shared_decimals)
195
+ Self::__initialize_oft(env, owner, token, endpoint, delegate, shared_decimals)
198
196
  }
199
197
  }
200
198
 
@@ -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 ====================