@layerzerolabs/protocol-stellar-v2 0.2.8

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 (265) hide show
  1. package/.turbo/turbo-build.log +727 -0
  2. package/.turbo/turbo-lint.log +158 -0
  3. package/.turbo/turbo-test.log +796 -0
  4. package/Cargo.lock +2237 -0
  5. package/Cargo.toml +63 -0
  6. package/clippy.toml +7 -0
  7. package/contracts/common-macros/Cargo.toml +20 -0
  8. package/contracts/common-macros/src/error.rs +53 -0
  9. package/contracts/common-macros/src/event.rs +16 -0
  10. package/contracts/common-macros/src/lib.rs +255 -0
  11. package/contracts/common-macros/src/ownable.rs +63 -0
  12. package/contracts/common-macros/src/snapshots/common_macros__tests__tests__snapshot_generated_storage_code.snap +310 -0
  13. package/contracts/common-macros/src/storage.rs +439 -0
  14. package/contracts/common-macros/src/tests.rs +287 -0
  15. package/contracts/common-macros/src/ttl_configurable.rs +60 -0
  16. package/contracts/endpoint-v2/ARCHITECTURE.md +233 -0
  17. package/contracts/endpoint-v2/Cargo.toml +30 -0
  18. package/contracts/endpoint-v2/src/constants.rs +52 -0
  19. package/contracts/endpoint-v2/src/endpoint_v2.rs +305 -0
  20. package/contracts/endpoint-v2/src/errors.rs +29 -0
  21. package/contracts/endpoint-v2/src/events.rs +207 -0
  22. package/contracts/endpoint-v2/src/interfaces/layerzero_composer.rs +26 -0
  23. package/contracts/endpoint-v2/src/interfaces/layerzero_endpoint_v2.rs +170 -0
  24. package/contracts/endpoint-v2/src/interfaces/layerzero_receiver.rs +43 -0
  25. package/contracts/endpoint-v2/src/interfaces/message_lib.rs +62 -0
  26. package/contracts/endpoint-v2/src/interfaces/message_lib_manager.rs +220 -0
  27. package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +121 -0
  28. package/contracts/endpoint-v2/src/interfaces/messaging_composer.rs +63 -0
  29. package/contracts/endpoint-v2/src/interfaces/mod.rs +17 -0
  30. package/contracts/endpoint-v2/src/interfaces/send_lib.rs +70 -0
  31. package/contracts/endpoint-v2/src/lib.rs +22 -0
  32. package/contracts/endpoint-v2/src/message_lib_manager.rs +315 -0
  33. package/contracts/endpoint-v2/src/messaging_channel.rs +218 -0
  34. package/contracts/endpoint-v2/src/messaging_composer.rs +76 -0
  35. package/contracts/endpoint-v2/src/storage.rs +78 -0
  36. package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +131 -0
  37. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +237 -0
  38. package/contracts/endpoint-v2/src/tests/endpoint_v2/delegate.rs +42 -0
  39. package/contracts/endpoint-v2/src/tests/endpoint_v2/initializable.rs +76 -0
  40. package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +211 -0
  41. package/contracts/endpoint-v2/src/tests/endpoint_v2/mod.rs +18 -0
  42. package/contracts/endpoint-v2/src/tests/endpoint_v2/native_token.rs +10 -0
  43. package/contracts/endpoint-v2/src/tests/endpoint_v2/owner.rs +10 -0
  44. package/contracts/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +424 -0
  45. package/contracts/endpoint-v2/src/tests/endpoint_v2/quote.rs +144 -0
  46. package/contracts/endpoint-v2/src/tests/endpoint_v2/recover_token.rs +72 -0
  47. package/contracts/endpoint-v2/src/tests/endpoint_v2/require_oapp_auth.rs +29 -0
  48. package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +513 -0
  49. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +43 -0
  50. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +27 -0
  51. package/contracts/endpoint-v2/src/tests/endpoint_v2/transfer_ownership.rs +30 -0
  52. package/contracts/endpoint-v2/src/tests/endpoint_v2/ttl_config.rs +202 -0
  53. package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +59 -0
  54. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +172 -0
  55. package/contracts/endpoint-v2/src/tests/endpoint_v2/zro.rs +23 -0
  56. package/contracts/endpoint-v2/src/tests/message_lib_manager/mod.rs +10 -0
  57. package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +131 -0
  58. package/contracts/endpoint-v2/src/tests/message_lib_manager/require_registered.rs +35 -0
  59. package/contracts/endpoint-v2/src/tests/message_lib_manager/require_supported_eid.rs +28 -0
  60. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_config.rs +79 -0
  61. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +246 -0
  62. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +285 -0
  63. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +180 -0
  64. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +405 -0
  65. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +80 -0
  66. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +131 -0
  67. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +358 -0
  68. package/contracts/endpoint-v2/src/tests/messaging_channel/clear.rs +316 -0
  69. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_nonce.rs +288 -0
  70. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_payload_hash.rs +316 -0
  71. package/contracts/endpoint-v2/src/tests/messaging_channel/internal.rs +388 -0
  72. package/contracts/endpoint-v2/src/tests/messaging_channel/lazy_inbound_nonce.rs +307 -0
  73. package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +10 -0
  74. package/contracts/endpoint-v2/src/tests/messaging_channel/next_guid.rs +239 -0
  75. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +324 -0
  76. package/contracts/endpoint-v2/src/tests/messaging_channel/outbound_nonce.rs +242 -0
  77. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +232 -0
  78. package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +212 -0
  79. package/contracts/endpoint-v2/src/tests/messaging_composer/compose_queue.rs +213 -0
  80. package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +269 -0
  81. package/contracts/endpoint-v2/src/tests/messaging_composer/mod.rs +4 -0
  82. package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +173 -0
  83. package/contracts/endpoint-v2/src/tests/mock.rs +132 -0
  84. package/contracts/endpoint-v2/src/tests/mod.rs +12 -0
  85. package/contracts/endpoint-v2/src/tests/util/build_payload.rs +126 -0
  86. package/contracts/endpoint-v2/src/tests/util/compute_guid.rs +82 -0
  87. package/contracts/endpoint-v2/src/tests/util/keccak256.rs +115 -0
  88. package/contracts/endpoint-v2/src/tests/util/mod.rs +3 -0
  89. package/contracts/endpoint-v2/src/util.rs +52 -0
  90. package/contracts/message-libs/Cargo.toml +12 -0
  91. package/contracts/message-libs/block-message-lib/Cargo.toml +19 -0
  92. package/contracts/message-libs/block-message-lib/src/lib.rs +70 -0
  93. package/contracts/message-libs/lib.rs +2 -0
  94. package/contracts/message-libs/message-lib-common/Cargo.toml +24 -0
  95. package/contracts/message-libs/message-lib-common/src/errors.rs +20 -0
  96. package/contracts/message-libs/message-lib-common/src/interfaces/dvn.rs +55 -0
  97. package/contracts/message-libs/message-lib-common/src/interfaces/executor.rs +46 -0
  98. package/contracts/message-libs/message-lib-common/src/interfaces/mod.rs +7 -0
  99. package/contracts/message-libs/message-lib-common/src/interfaces/treasury.rs +17 -0
  100. package/contracts/message-libs/message-lib-common/src/lib.rs +14 -0
  101. package/contracts/message-libs/message-lib-common/src/packet_codec_v1.rs +99 -0
  102. package/contracts/message-libs/message-lib-common/src/testing_utils.rs +27 -0
  103. package/contracts/message-libs/message-lib-common/src/tests/mod.rs +2 -0
  104. package/contracts/message-libs/message-lib-common/src/tests/packet_codec_v1.rs +162 -0
  105. package/contracts/message-libs/message-lib-common/src/tests/worker_options.rs +319 -0
  106. package/contracts/message-libs/message-lib-common/src/worker_options.rs +190 -0
  107. package/contracts/message-libs/simple-message-lib/Cargo.toml +26 -0
  108. package/contracts/message-libs/simple-message-lib/src/errors.rs +11 -0
  109. package/contracts/message-libs/simple-message-lib/src/lib.rs +14 -0
  110. package/contracts/message-libs/simple-message-lib/src/simple_message_lib.rs +136 -0
  111. package/contracts/message-libs/simple-message-lib/src/storage.rs +27 -0
  112. package/contracts/message-libs/simple-message-lib/src/test.rs +280 -0
  113. package/contracts/message-libs/treasury/Cargo.toml +27 -0
  114. package/contracts/message-libs/treasury/src/errors.rs +10 -0
  115. package/contracts/message-libs/treasury/src/events.rs +28 -0
  116. package/contracts/message-libs/treasury/src/interfaces/mod.rs +3 -0
  117. package/contracts/message-libs/treasury/src/interfaces/zro_fee_lib.rs +20 -0
  118. package/contracts/message-libs/treasury/src/lib.rs +20 -0
  119. package/contracts/message-libs/treasury/src/storage.rs +18 -0
  120. package/contracts/message-libs/treasury/src/tests/mod.rs +2 -0
  121. package/contracts/message-libs/treasury/src/tests/setup.rs +112 -0
  122. package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +562 -0
  123. package/contracts/message-libs/treasury/src/treasury.rs +140 -0
  124. package/contracts/message-libs/uln-302/Cargo.toml +28 -0
  125. package/contracts/message-libs/uln-302/src/config_validation.rs +173 -0
  126. package/contracts/message-libs/uln-302/src/errors.rs +29 -0
  127. package/contracts/message-libs/uln-302/src/events.rs +72 -0
  128. package/contracts/message-libs/uln-302/src/interfaces/mod.rs +5 -0
  129. package/contracts/message-libs/uln-302/src/interfaces/receive.rs +82 -0
  130. package/contracts/message-libs/uln-302/src/interfaces/send.rs +159 -0
  131. package/contracts/message-libs/uln-302/src/lib.rs +20 -0
  132. package/contracts/message-libs/uln-302/src/receive.rs +199 -0
  133. package/contracts/message-libs/uln-302/src/send.rs +349 -0
  134. package/contracts/message-libs/uln-302/src/storage.rs +47 -0
  135. package/contracts/message-libs/uln-302/src/tests/config/mod.rs +2 -0
  136. package/contracts/message-libs/uln-302/src/tests/config/oapp_uln_config.rs +291 -0
  137. package/contracts/message-libs/uln-302/src/tests/config/uln_config.rs +163 -0
  138. package/contracts/message-libs/uln-302/src/tests/mod.rs +7 -0
  139. package/contracts/message-libs/uln-302/src/tests/receive_uln302/commit_verification.rs +183 -0
  140. package/contracts/message-libs/uln-302/src/tests/receive_uln302/confirmations.rs +128 -0
  141. package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +104 -0
  142. package/contracts/message-libs/uln-302/src/tests/receive_uln302/mod.rs +66 -0
  143. package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +79 -0
  144. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verifiable.rs +463 -0
  145. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +173 -0
  146. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +132 -0
  147. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +117 -0
  148. package/contracts/message-libs/uln-302/src/tests/send_uln302/mod.rs +6 -0
  149. package/contracts/message-libs/uln-302/src/tests/send_uln302/quote.rs +586 -0
  150. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +834 -0
  151. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +95 -0
  152. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +80 -0
  153. package/contracts/message-libs/uln-302/src/tests/setup.rs +268 -0
  154. package/contracts/message-libs/uln-302/src/tests/testing_utils.rs +47 -0
  155. package/contracts/message-libs/uln-302/src/tests/uln302/get_app_receive_uln_config.rs +51 -0
  156. package/contracts/message-libs/uln-302/src/tests/uln302/get_app_send_uln_config.rs +51 -0
  157. package/contracts/message-libs/uln-302/src/tests/uln302/get_oapp_executor_config.rs +48 -0
  158. package/contracts/message-libs/uln-302/src/tests/uln302/mod.rs +4 -0
  159. package/contracts/message-libs/uln-302/src/tests/uln302/set_config.rs +998 -0
  160. package/contracts/message-libs/uln-302/src/uln302.rs +117 -0
  161. package/contracts/oapp-macros/Cargo.toml +21 -0
  162. package/contracts/oapp-macros/src/lib.rs +408 -0
  163. package/contracts/oapp-macros/src/oapp_core.rs +49 -0
  164. package/contracts/oapp-macros/src/oapp_full.rs +15 -0
  165. package/contracts/oapp-macros/src/oapp_options_type3.rs +46 -0
  166. package/contracts/oapp-macros/src/oapp_receiver.rs +67 -0
  167. package/contracts/oapp-macros/src/oapp_sender.rs +23 -0
  168. package/contracts/oapp-macros/src/util.rs +103 -0
  169. package/contracts/oapp-macros/tests/test_macros.rs +522 -0
  170. package/contracts/oapps/Cargo.toml +12 -0
  171. package/contracts/oapps/counter/Cargo.toml +24 -0
  172. package/contracts/oapps/counter/integration_tests/mod.rs +3 -0
  173. package/contracts/oapps/counter/integration_tests/setup.rs +201 -0
  174. package/contracts/oapps/counter/integration_tests/test_with_sml.rs +166 -0
  175. package/contracts/oapps/counter/integration_tests/utils.rs +144 -0
  176. package/contracts/oapps/counter/src/codec.rs +63 -0
  177. package/contracts/oapps/counter/src/counter.rs +235 -0
  178. package/contracts/oapps/counter/src/errors.rs +9 -0
  179. package/contracts/oapps/counter/src/lib.rs +16 -0
  180. package/contracts/oapps/counter/src/options.rs +30 -0
  181. package/contracts/oapps/counter/src/storage.rs +33 -0
  182. package/contracts/oapps/counter/src/tests/mod.rs +37 -0
  183. package/contracts/oapps/counter/src/tests/test_codec.rs +64 -0
  184. package/contracts/oapps/counter/src/tests/test_counter.rs +390 -0
  185. package/contracts/oapps/counter/src/u256_ext.rs +21 -0
  186. package/contracts/oapps/lib.rs +2 -0
  187. package/contracts/oapps/oapp/Cargo.toml +21 -0
  188. package/contracts/oapps/oapp/src/errors.rs +9 -0
  189. package/contracts/oapps/oapp/src/lib.rs +10 -0
  190. package/contracts/oapps/oapp/src/oapp_core.rs +92 -0
  191. package/contracts/oapps/oapp/src/oapp_options_type3.rs +89 -0
  192. package/contracts/oapps/oapp/src/oapp_receiver.rs +72 -0
  193. package/contracts/oapps/oapp/src/oapp_sender.rs +66 -0
  194. package/contracts/oapps/oapp/src/tests/mod.rs +4 -0
  195. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +162 -0
  196. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +180 -0
  197. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +157 -0
  198. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +283 -0
  199. package/contracts/utils/Cargo.toml +21 -0
  200. package/contracts/utils/src/buffer_reader.rs +143 -0
  201. package/contracts/utils/src/buffer_writer.rs +117 -0
  202. package/contracts/utils/src/bytes_ext.rs +19 -0
  203. package/contracts/utils/src/errors.rs +30 -0
  204. package/contracts/utils/src/lib.rs +15 -0
  205. package/contracts/utils/src/option_ext.rs +38 -0
  206. package/contracts/utils/src/ownable.rs +88 -0
  207. package/contracts/utils/src/testing_utils.rs +100 -0
  208. package/contracts/utils/src/tests/buffer_reader.rs +1006 -0
  209. package/contracts/utils/src/tests/buffer_writer.rs +330 -0
  210. package/contracts/utils/src/tests/bytes_ext.rs +77 -0
  211. package/contracts/utils/src/tests/mod.rs +4 -0
  212. package/contracts/utils/src/tests/ownable.rs +149 -0
  213. package/contracts/utils/src/ttl.rs +164 -0
  214. package/contracts/workers/Cargo.toml +13 -0
  215. package/contracts/workers/executor/Cargo.toml +26 -0
  216. package/contracts/workers/executor/src/events.rs +22 -0
  217. package/contracts/workers/executor/src/executor.rs +347 -0
  218. package/contracts/workers/executor/src/interfaces/executor.rs +40 -0
  219. package/contracts/workers/executor/src/interfaces/mod.rs +5 -0
  220. package/contracts/workers/executor/src/interfaces/types.rs +51 -0
  221. package/contracts/workers/executor/src/lib.rs +10 -0
  222. package/contracts/workers/executor/src/storage.rs +23 -0
  223. package/contracts/workers/lib.rs +2 -0
  224. package/contracts/workers/worker-common/Cargo.toml +18 -0
  225. package/contracts/workers/worker-common/src/constants.rs +17 -0
  226. package/contracts/workers/worker-common/src/errors.rs +6 -0
  227. package/contracts/workers/worker-common/src/events.rs +34 -0
  228. package/contracts/workers/worker-common/src/interfaces/executor_fee_lib.rs +35 -0
  229. package/contracts/workers/worker-common/src/interfaces/mod.rs +7 -0
  230. package/contracts/workers/worker-common/src/interfaces/price_feed.rs +40 -0
  231. package/contracts/workers/worker-common/src/interfaces/worker.rs +60 -0
  232. package/contracts/workers/worker-common/src/lib.rs +19 -0
  233. package/contracts/workers/worker-common/src/storage.rs +32 -0
  234. package/contracts/workers/worker-common/src/worker_common.rs +166 -0
  235. package/package.json +25 -0
  236. package/rust-toolchain.toml +4 -0
  237. package/rustfmt.toml +17 -0
  238. package/sdk/.turbo/turbo-build.log +4 -0
  239. package/sdk/dist/generated/bml.d.ts +452 -0
  240. package/sdk/dist/generated/bml.js +72 -0
  241. package/sdk/dist/generated/counter.d.ts +824 -0
  242. package/sdk/dist/generated/counter.js +125 -0
  243. package/sdk/dist/generated/endpoint.d.ts +1676 -0
  244. package/sdk/dist/generated/endpoint.js +216 -0
  245. package/sdk/dist/generated/sml.d.ts +810 -0
  246. package/sdk/dist/generated/sml.js +132 -0
  247. package/sdk/dist/generated/uln302.d.ts +1227 -0
  248. package/sdk/dist/generated/uln302.js +185 -0
  249. package/sdk/dist/index.d.ts +5 -0
  250. package/sdk/dist/index.js +5 -0
  251. package/sdk/node_modules/.bin/tsc +21 -0
  252. package/sdk/node_modules/.bin/tsserver +21 -0
  253. package/sdk/node_modules/.bin/vitest +21 -0
  254. package/sdk/node_modules/.bin/zx +21 -0
  255. package/sdk/package.json +40 -0
  256. package/sdk/src/index.ts +5 -0
  257. package/sdk/test/index.test.ts +271 -0
  258. package/sdk/test/suites/constants.ts +13 -0
  259. package/sdk/test/suites/deploy.ts +277 -0
  260. package/sdk/test/suites/localnet.ts +42 -0
  261. package/sdk/test/suites/scan.ts +189 -0
  262. package/sdk/tsconfig.json +106 -0
  263. package/tools/ts-bindings-gen/Cargo.toml +14 -0
  264. package/tools/ts-bindings-gen/src/main.rs +147 -0
  265. package/turbo.json +12 -0
@@ -0,0 +1,283 @@
1
+ use crate as oapp;
2
+ use crate::{errors::OAppError, oapp_core::OAppCore};
3
+ use endpoint_v2::{MessagingFee, MessagingParams, MessagingReceipt};
4
+ use soroban_sdk::{
5
+ contract, contractimpl, symbol_short,
6
+ testutils::{Address as _, MockAuth, MockAuthInvoke},
7
+ token::{StellarAssetClient, TokenClient},
8
+ Address, Bytes, BytesN, Env, IntoVal,
9
+ };
10
+ use utils::ownable::Ownable;
11
+
12
+ // Mock Endpoint contract
13
+ #[contract]
14
+ pub struct MockEndpoint;
15
+
16
+ #[contractimpl]
17
+ impl MockEndpoint {
18
+ pub fn __constructor(env: Env, zro_token: &Address, native_token: &Address) {
19
+ env.storage().instance().set(&symbol_short!("zro"), zro_token);
20
+ env.storage().instance().set(&symbol_short!("ntk"), native_token);
21
+ }
22
+
23
+ pub fn set_delegate(_env: Env, _oapp: Address, _delegate: Option<Address>) {
24
+ // do nothing in mock
25
+ }
26
+
27
+ pub fn quote(_env: Env, _sender: Address, params: MessagingParams) -> MessagingFee {
28
+ MessagingFee { native_fee: 1000, zro_fee: if params.pay_in_zro { 500 } else { 0 } }
29
+ }
30
+
31
+ pub fn send(env: Env, _sender: Address, params: MessagingParams, _refund_address: Address) -> MessagingReceipt {
32
+ // Return mock receipt
33
+ MessagingReceipt {
34
+ guid: BytesN::from_array(&env, &[1u8; 32]),
35
+ nonce: 1,
36
+ fee: MessagingFee { native_fee: 1000, zro_fee: if params.pay_in_zro { 500 } else { 0 } },
37
+ }
38
+ }
39
+
40
+ pub fn zro(env: Env) -> Option<Address> {
41
+ // Return a mock ZRO token address
42
+ env.storage().instance().get(&symbol_short!("zro")).unwrap()
43
+ }
44
+
45
+ pub fn native_token(env: Env) -> Address {
46
+ env.storage().instance().get(&symbol_short!("ntk")).unwrap()
47
+ }
48
+ }
49
+
50
+ #[oapp_macros::oapp_sender]
51
+ pub struct DummyOAppSender;
52
+
53
+ #[contractimpl]
54
+ impl DummyOAppSender {
55
+ pub fn __constructor(env: &Env, owner: &Address, endpoint: &Address) {
56
+ Self::__init_owner(env, owner);
57
+ Self::__oapp_initialize(env, endpoint, &None);
58
+ }
59
+
60
+ pub fn quote(env: &Env, dst_eid: u32, message: &Bytes, options: &Bytes, pay_in_zro: bool) -> MessagingFee {
61
+ Self::__quote(env, dst_eid, message, options, pay_in_zro)
62
+ }
63
+
64
+ pub fn lz_send(
65
+ env: &Env,
66
+ sender: &Address,
67
+ dst_eid: u32,
68
+ message: &Bytes,
69
+ options: &Bytes,
70
+ fee: &MessagingFee,
71
+ refund_address: &Address,
72
+ ) -> MessagingReceipt {
73
+ sender.require_auth();
74
+ Self::__lz_send(env, sender, dst_eid, message, options, fee, refund_address)
75
+ }
76
+
77
+ pub fn pay_native(env: &Env, payer: &Address, native_fee: i128) {
78
+ payer.require_auth();
79
+ Self::__pay_native(env, payer, native_fee)
80
+ }
81
+
82
+ pub fn pay_zro(env: &Env, payer: &Address, zro_fee: i128) {
83
+ payer.require_auth();
84
+ Self::__pay_zro(env, payer, zro_fee)
85
+ }
86
+ }
87
+
88
+ const REMOTE_EID: u32 = 100;
89
+ const UNSET_EID: u32 = 999;
90
+
91
+ struct TestSetup<'a> {
92
+ env: Env,
93
+ #[allow(dead_code)]
94
+ token_admin: Address,
95
+ endpoint: Address,
96
+ #[allow(dead_code)]
97
+ owner: Address,
98
+ oapp_client: DummyOAppSenderClient<'a>,
99
+ native_token_client: TokenClient<'a>,
100
+ native_token_admin_client: StellarAssetClient<'a>,
101
+ zro_token_admin_client: StellarAssetClient<'a>,
102
+ }
103
+
104
+ fn setup<'a>() -> TestSetup<'a> {
105
+ let env = Env::default();
106
+
107
+ let owner = Address::generate(&env);
108
+
109
+ let token_admin = Address::generate(&env);
110
+ // Deploy mock tokens
111
+ let native_token_sac = env.register_stellar_asset_contract_v2(token_admin.clone());
112
+ let native_token = native_token_sac.address();
113
+ let native_token_client = TokenClient::new(&env, &native_token);
114
+ let native_token_admin_client = StellarAssetClient::new(&env, &native_token);
115
+
116
+ let zro_token_sac = env.register_stellar_asset_contract_v2(token_admin.clone());
117
+ let zro_token = zro_token_sac.address();
118
+ let zro_token_admin_client = StellarAssetClient::new(&env, &zro_token);
119
+
120
+ // Deploy mock endpoint
121
+ let endpoint = env.register(MockEndpoint, (&zro_token, &native_token));
122
+
123
+ // Deploy OApp
124
+ let oapp = env.register(DummyOAppSender, (&owner, &endpoint));
125
+ let oapp_client = DummyOAppSenderClient::new(&env, &oapp);
126
+
127
+ TestSetup {
128
+ env,
129
+ endpoint,
130
+ token_admin,
131
+ native_token_client,
132
+ native_token_admin_client,
133
+ zro_token_admin_client,
134
+ owner,
135
+ oapp_client,
136
+ }
137
+ }
138
+
139
+ #[test]
140
+ fn test_quote_with_peer_set() {
141
+ let TestSetup { env, owner, oapp_client, .. } = setup();
142
+
143
+ // Set peer for destination
144
+ let peer = BytesN::from_array(&env, &[1; 32]);
145
+ let peer_option = Some(peer.clone());
146
+ env.mock_auths(&[MockAuth {
147
+ address: &owner,
148
+ invoke: &MockAuthInvoke {
149
+ contract: &oapp_client.address,
150
+ fn_name: "set_peer",
151
+ args: (&REMOTE_EID, &peer_option).into_val(&env),
152
+ sub_invokes: &[],
153
+ },
154
+ }]);
155
+ oapp_client.set_peer(&REMOTE_EID, &peer_option);
156
+
157
+ let message = Bytes::from_array(&env, &[1, 2, 3, 4, 5]);
158
+ let options = Bytes::from_array(&env, &[6, 7, 8]);
159
+
160
+ // Test quote without ZRO
161
+ let fee = oapp_client.quote(&REMOTE_EID, &message, &options, &false);
162
+ assert!(fee.native_fee > 0);
163
+ assert_eq!(fee.zro_fee, 0);
164
+
165
+ // Test quote with ZRO
166
+ let fee_with_zro = oapp_client.quote(&REMOTE_EID, &message, &options, &true);
167
+ assert!(fee_with_zro.native_fee > 0);
168
+ assert!(fee_with_zro.zro_fee > 0);
169
+ }
170
+
171
+ #[test]
172
+ fn test_quote_without_peer_panics() {
173
+ let TestSetup { env, oapp_client, .. } = setup();
174
+
175
+ let message = Bytes::from_array(&env, &[1, 2, 3]);
176
+ let options = Bytes::from_array(&env, &[]);
177
+
178
+ // This should panic because no peer is set for UNSET_EID
179
+ let result = oapp_client.try_quote(&UNSET_EID, &message, &options, &false);
180
+ assert_eq!(result.err().unwrap().ok().unwrap(), OAppError::NoPeer.into());
181
+ }
182
+
183
+ #[test]
184
+ fn test_lz_send_native_only() {
185
+ let TestSetup { env, oapp_client, endpoint, native_token_client, native_token_admin_client, .. } = setup();
186
+
187
+ env.mock_all_auths();
188
+
189
+ // Setup peer
190
+ let peer = BytesN::from_array(&env, &[2; 32]);
191
+ oapp_client.set_peer(&REMOTE_EID, &Some(peer));
192
+
193
+ // Setup sender with funds
194
+ let sender = Address::generate(&env);
195
+ let initial_balance = 10000i128;
196
+ native_token_admin_client.mint(&sender, &initial_balance);
197
+
198
+ let message = Bytes::from_array(&env, &[1, 2, 3]);
199
+ let options = Bytes::from_array(&env, &[]);
200
+ let refund_address = Address::generate(&env);
201
+
202
+ let fee = MessagingFee { native_fee: 1000, zro_fee: 0 };
203
+
204
+ // Send message (auth is mocked automatically)
205
+ let receipt = oapp_client.lz_send(&sender, &REMOTE_EID, &message, &options, &fee, &refund_address);
206
+
207
+ // Verify receipt
208
+ assert_eq!(receipt.nonce, 1);
209
+ assert_eq!(receipt.fee.native_fee, fee.native_fee);
210
+
211
+ // Verify native token was transferred to endpoint
212
+ let sender_balance = native_token_client.balance(&sender);
213
+ assert_eq!(sender_balance, initial_balance - fee.native_fee);
214
+
215
+ let endpoint_balance = native_token_client.balance(&endpoint);
216
+ assert_eq!(endpoint_balance, fee.native_fee);
217
+ }
218
+
219
+ #[test]
220
+ fn test_lz_send_with_zro() {
221
+ let TestSetup { env, oapp_client, native_token_admin_client, zro_token_admin_client, .. } = setup();
222
+
223
+ env.mock_all_auths();
224
+
225
+ // Setup peer
226
+ let peer = BytesN::from_array(&env, &[3; 32]);
227
+ oapp_client.set_peer(&REMOTE_EID, &Some(peer));
228
+
229
+ // Setup sender with both native and ZRO funds
230
+ let fee = MessagingFee { native_fee: 1000, zro_fee: 500 };
231
+
232
+ let sender = Address::generate(&env);
233
+ native_token_admin_client.mint(&sender, &fee.native_fee);
234
+ zro_token_admin_client.mint(&sender, &fee.zro_fee);
235
+
236
+ let message = Bytes::from_array(&env, &[1, 2, 3, 4]);
237
+ let options = Bytes::from_array(&env, &[5]);
238
+ let refund_address = Address::generate(&env);
239
+
240
+ // Send message with ZRO payment
241
+ let receipt = oapp_client.lz_send(&sender, &REMOTE_EID, &message, &options, &fee, &refund_address);
242
+
243
+ assert_eq!(receipt.fee.zro_fee, fee.zro_fee);
244
+ }
245
+
246
+ #[test]
247
+ fn test_pay_native() {
248
+ let TestSetup { env, oapp_client, endpoint, native_token_admin_client, .. } = setup();
249
+
250
+ env.mock_all_auths();
251
+
252
+ let payer = Address::generate(&env);
253
+ let payment_amount = 2000i128;
254
+
255
+ // Fund the payer
256
+ native_token_admin_client.mint(&payer, &payment_amount);
257
+
258
+ // Make payment
259
+ oapp_client.pay_native(&payer, &payment_amount);
260
+
261
+ // Verify balances
262
+ assert_eq!(native_token_admin_client.balance(&payer), 0);
263
+ assert_eq!(native_token_admin_client.balance(&endpoint), payment_amount);
264
+ }
265
+
266
+ #[test]
267
+ #[should_panic(expected = "balance is not sufficient to spend")]
268
+ fn test_pay_native_insufficient_balance() {
269
+ let TestSetup { env, oapp_client, native_token_admin_client, .. } = setup();
270
+
271
+ env.mock_all_auths();
272
+
273
+ let balance = 500i128;
274
+ let payment_amount = 1000i128;
275
+
276
+ let payer = Address::generate(&env);
277
+
278
+ // Fund with less than required
279
+ native_token_admin_client.mint(&payer, &balance);
280
+
281
+ // This should panic due to insufficient balance
282
+ oapp_client.pay_native(&payer, &payment_amount);
283
+ }
@@ -0,0 +1,21 @@
1
+ [package]
2
+ name = "utils"
3
+ version.workspace = true
4
+ edition.workspace = true
5
+ license.workspace = true
6
+ publish = false
7
+
8
+ [lib]
9
+ crate-type = ["rlib"]
10
+ doctest = false
11
+
12
+ [features]
13
+ testutils = []
14
+
15
+ [dependencies]
16
+ soroban-sdk = { workspace = true }
17
+ common-macros = { workspace = true }
18
+
19
+ [dev-dependencies]
20
+ soroban-sdk = { workspace = true, features = ["testutils"] }
21
+ stellar-strkey = "0.0.14"
@@ -0,0 +1,143 @@
1
+ use soroban_sdk::{
2
+ address_payload::AddressPayload, assert_with_error, panic_with_error, Address, Bytes, BytesN, Env, U256,
3
+ };
4
+
5
+ use crate::{
6
+ buffer_writer::{ACCOUNT_PAYLOAD_TYPE, CONTRACT_PAYLOAD_TYPE},
7
+ bytes_ext::BytesExt,
8
+ errors::BufferReaderError,
9
+ };
10
+
11
+ /// Macro to generate read methods for primitive integer types (big-endian).
12
+ macro_rules! impl_read_uint {
13
+ ($($method:ident, $type:ty, $len:expr);* $(;)?) => {
14
+ $(
15
+ pub fn $method(&mut self) -> $type {
16
+ <$type>::from_be_bytes(self.read_bytes($len).to_array())
17
+ }
18
+ )*
19
+ };
20
+ }
21
+
22
+ /// A sequential reader for parsing binary data from a byte buffer.
23
+ ///
24
+ /// Maintains a position cursor that advances as data is read.
25
+ /// All integer reads are big-endian.
26
+ pub struct BufferReader<'a> {
27
+ buffer: &'a Bytes,
28
+ pos: u32,
29
+ }
30
+
31
+ impl<'a> BufferReader<'a> {
32
+ /// Creates a new reader starting at position 0.
33
+ pub fn new(buffer: &'a Bytes) -> Self {
34
+ Self { buffer, pos: 0 }
35
+ }
36
+
37
+ // TODO: should we pass and return a self instead of mutable reference?
38
+ /// Sets the absolute position in the buffer.
39
+ pub fn set_position(&mut self, pos: u32) -> &mut Self {
40
+ assert_with_error!(self.buffer.env(), pos <= self.buffer.len(), BufferReaderError::InvalidLength);
41
+ self.pos = pos;
42
+ self
43
+ }
44
+
45
+ /// Advances the position by `len` bytes without reading.
46
+ pub fn skip(&mut self, len: u32) -> &mut Self {
47
+ self.set_position(self.pos + len)
48
+ }
49
+
50
+ /// Moves the position backwards by `len` bytes.
51
+ pub fn rewind(&mut self, len: u32) -> &mut Self {
52
+ assert_with_error!(self.buffer.env(), self.pos >= len, BufferReaderError::InvalidLength);
53
+ self.pos -= len;
54
+ self
55
+ }
56
+
57
+ // Generates: read_u8 (1 byte), read_u16 (2 bytes), read_u32 (4 bytes), read_u64 (8 bytes), read_u128 (16 bytes)
58
+ impl_read_uint!(read_u8, u8, 1; read_u16, u16, 2; read_u32, u32, 4; read_u64, u64, 8; read_u128, u128, 16);
59
+
60
+ /// Reads a boolean (1 byte, non-zero = true).
61
+ pub fn read_bool(&mut self) -> bool {
62
+ self.read_u8() != 0
63
+ }
64
+
65
+ /// Reads a U256 (32 bytes, big-endian).
66
+ pub fn read_u256(&mut self) -> U256 {
67
+ U256::from_be_bytes(self.buffer.env(), &self.read_bytes(32))
68
+ }
69
+
70
+ /// Reads a Stellar address (33 bytes: 1 type + 32 payload).
71
+ pub fn read_address(&mut self) -> Address {
72
+ let payload_type = self.read_u8();
73
+ let payload = self.read_address_payload();
74
+ self.compose_address(payload_type, payload)
75
+ }
76
+
77
+ /// Reads an address payload only from the buffer (32 bytes).
78
+ pub fn read_address_payload(&mut self) -> BytesN<32> {
79
+ self.read_bytes_n()
80
+ }
81
+
82
+ /// Reads N bytes as a fixed-size BytesN<N>.
83
+ pub fn read_bytes_n<const N: usize>(&mut self) -> BytesN<N> {
84
+ BytesN::<N>::from_array(self.buffer.env(), &self.read_bytes(N as u32).to_array())
85
+ }
86
+
87
+ /// Reads `len` bytes from current position and advances.
88
+ pub fn read_bytes(&mut self, len: u32) -> Bytes {
89
+ let end = self.pos + len;
90
+ assert_with_error!(self.buffer.env(), self.buffer.len() >= end, BufferReaderError::InvalidLength);
91
+
92
+ let value = self.buffer.slice(self.pos..end);
93
+ self.pos = end;
94
+ value
95
+ }
96
+
97
+ /// Reads all remaining bytes from current position to end.
98
+ pub fn read_bytes_until_end(&mut self) -> Bytes {
99
+ self.read_bytes(self.remaining())
100
+ }
101
+
102
+ /// Returns the current read position.
103
+ pub fn position(&self) -> u32 {
104
+ self.pos
105
+ }
106
+
107
+ /// Returns a reference to the underlying buffer.
108
+ pub fn buffer(&self) -> &Bytes {
109
+ self.buffer
110
+ }
111
+
112
+ /// Returns the total length of the buffer.
113
+ pub fn len(&self) -> u32 {
114
+ self.buffer.len()
115
+ }
116
+
117
+ /// Returns true if the buffer is empty.
118
+ pub fn is_empty(&self) -> bool {
119
+ self.buffer.is_empty()
120
+ }
121
+
122
+ /// Returns the number of bytes remaining after current position.
123
+ pub fn remaining(&self) -> u32 {
124
+ self.buffer.len() - self.pos
125
+ }
126
+
127
+ /// Returns the Soroban environment reference.
128
+ pub fn env(&self) -> &Env {
129
+ self.buffer.env()
130
+ }
131
+
132
+ // === Internal Functions ===
133
+
134
+ /// Compose an address from its type byte and 32-byte payload.
135
+ fn compose_address(&self, payload_type: u8, payload: BytesN<32>) -> Address {
136
+ let addr_payload = match payload_type {
137
+ ACCOUNT_PAYLOAD_TYPE => AddressPayload::AccountIdPublicKeyEd25519(payload),
138
+ CONTRACT_PAYLOAD_TYPE => AddressPayload::ContractIdHash(payload),
139
+ _ => panic_with_error!(self.buffer.env(), BufferReaderError::InvalidAddressPayload),
140
+ };
141
+ Address::from_payload(self.buffer.env(), addr_payload)
142
+ }
143
+ }
@@ -0,0 +1,117 @@
1
+ use soroban_sdk::{address_payload::AddressPayload, Address, Bytes, BytesN, Env, U256};
2
+
3
+ use crate::{errors::BufferWriterError, option_ext::OptionExt};
4
+
5
+ /// Macro to generate write methods for primitive integer types (big-endian).
6
+ macro_rules! impl_write_uint {
7
+ ($($method:ident, $type:ty);* $(;)?) => {
8
+ $(
9
+ pub fn $method(&mut self, value: $type) -> &mut Self {
10
+ self.buffer.extend_from_slice(&value.to_be_bytes());
11
+ self
12
+ }
13
+ )*
14
+ };
15
+ }
16
+
17
+ pub const ACCOUNT_PAYLOAD_TYPE: u8 = 0;
18
+ pub const CONTRACT_PAYLOAD_TYPE: u8 = 1;
19
+
20
+ /// A writer for serializing data to a byte buffer.
21
+ ///
22
+ /// The writer maintains an internal byte buffer and provides methods to write
23
+ /// various data types in big-endian format. All write operations return a
24
+ /// mutable reference to the writer, enabling method chaining.
25
+ ///
26
+ /// # Example
27
+ /// ```ignore
28
+ /// let mut writer = BufferWriter::new(&env);
29
+ /// writer.write_u32(0x12345678)
30
+ /// .write_bool(true)
31
+ /// .write_bytes32(&bytes32);
32
+ /// let bytes = writer.to_bytes();
33
+ /// ```
34
+ pub struct BufferWriter {
35
+ buffer: Bytes,
36
+ }
37
+
38
+ impl BufferWriter {
39
+ /// Create a new empty writer.
40
+ pub fn new(env: &Env) -> Self {
41
+ Self { buffer: Bytes::new(env) }
42
+ }
43
+
44
+ /// Create a new writer initialized with existing data.
45
+ pub fn from_bytes(buffer: Bytes) -> Self {
46
+ Self { buffer }
47
+ }
48
+
49
+ // Generates: write_u8 (1 byte), write_u16 (2 bytes), write_u32 (4 bytes), write_u64 (8 bytes), write_u128 (16 bytes)
50
+ impl_write_uint!(write_u8, u8; write_u16, u16; write_u32, u32; write_u64, u64; write_u128, u128);
51
+
52
+ /// Write a boolean value to the buffer (true as 1, false as 0).
53
+ pub fn write_bool(&mut self, value: bool) -> &mut Self {
54
+ self.write_u8(if value { 1 } else { 0 })
55
+ }
56
+
57
+ /// Write an unsigned 256-bit integer in big-endian format.
58
+ pub fn write_u256(&mut self, value: U256) -> &mut Self {
59
+ self.buffer.append(&value.to_be_bytes());
60
+ self
61
+ }
62
+
63
+ /// Write a byte slice to the buffer (appends without length prefix).
64
+ pub fn write_bytes(&mut self, bytes: &Bytes) -> &mut Self {
65
+ self.buffer.append(bytes);
66
+ self
67
+ }
68
+
69
+ /// Write a fixed-size BytesN<N> to the buffer.
70
+ pub fn write_bytes_n<const N: usize>(&mut self, bytes_n: &BytesN<N>) -> &mut Self {
71
+ self.buffer.extend_from_array(&bytes_n.to_array());
72
+ self
73
+ }
74
+
75
+ /// Write an address type and payload to the buffer (33 bytes: 1 type + 32 payload).
76
+ pub fn write_address(&mut self, address: &Address) -> &mut Self {
77
+ let (payload_type, payload) = self.decompose_address(address);
78
+ self.write_u8(payload_type).write_bytes_n(&payload)
79
+ }
80
+
81
+ /// Write an address payload only to the buffer (32 bytes).
82
+ pub fn write_address_payload(&mut self, address: &Address) -> &mut Self {
83
+ let (_, payload) = self.decompose_address(address);
84
+ self.write_bytes_n(&payload)
85
+ }
86
+
87
+ /// Get the complete buffer as a Bytes, consuming the writer.
88
+ pub fn to_bytes(self) -> Bytes {
89
+ let Self { buffer } = self;
90
+ buffer
91
+ }
92
+
93
+ /// Get the current length of the buffer.
94
+ pub fn len(&self) -> u32 {
95
+ self.buffer.len()
96
+ }
97
+
98
+ /// Check if the buffer is empty.
99
+ pub fn is_empty(&self) -> bool {
100
+ self.buffer.is_empty()
101
+ }
102
+
103
+ /// Get the environment from the buffer.
104
+ pub fn env(&self) -> &Env {
105
+ self.buffer.env()
106
+ }
107
+
108
+ // === Internal Functions ===
109
+
110
+ /// Decompose an address into its type byte and 32-byte payload.
111
+ fn decompose_address(&self, address: &Address) -> (u8, BytesN<32>) {
112
+ match address.to_payload().unwrap_or_panic(self.buffer.env(), BufferWriterError::InvalidAddressPayload) {
113
+ AddressPayload::AccountIdPublicKeyEd25519(p) => (ACCOUNT_PAYLOAD_TYPE, p),
114
+ AddressPayload::ContractIdHash(p) => (CONTRACT_PAYLOAD_TYPE, p),
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,19 @@
1
+ use soroban_sdk::{assert_with_error, Bytes};
2
+
3
+ use crate::errors::BytesExtError;
4
+
5
+ /// Extension trait for `Bytes` to convert to fixed-size arrays
6
+ pub trait BytesExt {
7
+ /// Copies the entire bytes into a fixed-size array.
8
+ /// Panics if bytes length != N.
9
+ fn to_array<const N: usize>(&self) -> [u8; N];
10
+ }
11
+
12
+ impl BytesExt for Bytes {
13
+ fn to_array<const N: usize>(&self) -> [u8; N] {
14
+ assert_with_error!(self.env(), self.len() == N as u32, BytesExtError::LengthMismatch);
15
+ let mut buf = [0u8; N];
16
+ self.copy_into_slice(&mut buf);
17
+ buf
18
+ }
19
+ }
@@ -0,0 +1,30 @@
1
+ use common_macros::contract_error;
2
+
3
+ #[contract_error]
4
+ pub enum BufferReaderError {
5
+ InvalidLength = 10000,
6
+ InvalidAddressPayload,
7
+ }
8
+
9
+ #[contract_error]
10
+ pub enum BufferWriterError {
11
+ InvalidAddressPayload = 10100,
12
+ }
13
+
14
+ #[contract_error]
15
+ pub enum TtlError {
16
+ InvalidTtlConfig = 10200,
17
+ TtlConfigFrozen,
18
+ TtlConfigAlreadyFrozen,
19
+ }
20
+
21
+ #[contract_error]
22
+ pub enum OwnableError {
23
+ OwnerAlreadySet = 10300,
24
+ OwnerNotSet,
25
+ }
26
+
27
+ #[contract_error]
28
+ pub enum BytesExtError {
29
+ LengthMismatch = 10400,
30
+ }
@@ -0,0 +1,15 @@
1
+ #![no_std]
2
+
3
+ pub mod buffer_reader;
4
+ pub mod buffer_writer;
5
+ pub mod bytes_ext;
6
+ pub mod errors;
7
+ pub mod option_ext;
8
+ pub mod ownable;
9
+ pub mod ttl;
10
+
11
+ #[cfg(test)]
12
+ mod tests;
13
+
14
+ #[cfg(any(test, feature = "testutils"))]
15
+ pub mod testing_utils;
@@ -0,0 +1,38 @@
1
+ use soroban_sdk::{panic_with_error, Env};
2
+
3
+ /// Extension trait for `Option<T>` that provides Soroban-specific unwrapping utilities.
4
+ ///
5
+ /// This trait extends the standard `Option` type with methods that integrate with
6
+ /// Soroban's error handling system, allowing for more descriptive panics when
7
+ /// unwrapping fails.
8
+ pub trait OptionExt<T> {
9
+ /// Unwraps the `Option`, returning the contained value if `Some`,
10
+ /// or panics with the provided error if `None`.
11
+ ///
12
+ /// # Arguments
13
+ /// * `env` - The Soroban environment, required for error propagation.
14
+ /// * `error` - The error to emit if the `Option` is `None`. Must be convertible into a `soroban_sdk::Error`.
15
+ ///
16
+ /// # Returns
17
+ /// The contained value if `Some`.
18
+ ///
19
+ /// # Panics
20
+ /// Panics with the specified error if the `Option` is `None`.
21
+ fn unwrap_or_panic<E>(self, env: &Env, error: E) -> T
22
+ where
23
+ E: Into<soroban_sdk::Error>;
24
+ }
25
+
26
+ impl<T> OptionExt<T> for Option<T> {
27
+ fn unwrap_or_panic<E>(self, env: &Env, error: E) -> T
28
+ where
29
+ E: Into<soroban_sdk::Error>,
30
+ {
31
+ match self {
32
+ // Return the inner value if present
33
+ Some(val) => val,
34
+ // Panic with the provided error if None, using Soroban's error macro
35
+ None => panic_with_error!(env, error),
36
+ }
37
+ }
38
+ }