@layerzerolabs/protocol-stellar-v2 0.2.34 → 0.2.36

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 (135) hide show
  1. package/.turbo/turbo-build.log +281 -276
  2. package/.turbo/turbo-lint.log +209 -211
  3. package/.turbo/turbo-test.log +1705 -1701
  4. package/Cargo.lock +10 -10
  5. package/Cargo.toml +1 -1
  6. package/contracts/common-macros/src/auth.rs +5 -5
  7. package/contracts/common-macros/src/lib.rs +69 -0
  8. package/contracts/common-macros/src/rbac.rs +90 -0
  9. package/contracts/common-macros/src/storage.rs +7 -5
  10. package/contracts/common-macros/src/tests/lz_contract.rs +5 -7
  11. package/contracts/common-macros/src/tests/mod.rs +1 -0
  12. package/contracts/common-macros/src/tests/rbac.rs +420 -0
  13. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +4 -4
  14. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +5 -12
  15. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__rbac__snapshot_preserve_function_signature.snap +17 -0
  16. package/contracts/common-macros/src/tests/storage/parse_name.rs +0 -1
  17. package/contracts/common-macros/src/tests/storage/snapshots/common_macros__tests__storage__generate_storage__snapshot_generated_storage_code.snap +3 -3
  18. package/contracts/endpoint-v2/src/endpoint_v2.rs +5 -4
  19. package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +7 -8
  20. package/contracts/endpoint-v2/src/messaging_channel.rs +78 -45
  21. package/contracts/endpoint-v2/src/storage.rs +8 -3
  22. package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +2 -2
  23. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +12 -15
  24. package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +46 -9
  25. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +7 -23
  26. package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +23 -20
  27. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +94 -1
  28. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_nonce.rs +17 -15
  29. package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -1
  30. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +48 -13
  31. package/contracts/endpoint-v2/src/tests/messaging_channel/pending_inbound_nonces.rs +111 -0
  32. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +15 -25
  33. package/contracts/layerzero-views/src/layerzero_view.rs +2 -2
  34. package/contracts/layerzero-views/src/tests/layerzero_view_tests.rs +3 -4
  35. package/contracts/layerzero-views/src/tests/setup.rs +0 -21
  36. package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_default.rs +1 -1
  37. package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig.rs +1 -1
  38. package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig_upgradeable.rs +1 -1
  39. package/contracts/macro-integration-tests/tests/runtime/multisig/self_auth.rs +1 -1
  40. package/contracts/macro-integration-tests/tests/runtime/ownable/initialization.rs +8 -5
  41. package/contracts/macro-integration-tests/tests/runtime/ownable/ownership_transfer.rs +2 -2
  42. package/contracts/macro-integration-tests/tests/runtime/rbac/guard_behavior.rs +91 -0
  43. package/contracts/macro-integration-tests/tests/runtime/rbac/mod.rs +30 -0
  44. package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/configuration.rs +2 -2
  45. package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +4 -4
  46. package/contracts/macro-integration-tests/tests/ui/lz_contract/pass/basic.rs +1 -1
  47. package/contracts/macro-integration-tests/tests/ui/ownable/pass/basic.rs +1 -1
  48. package/contracts/macro-integration-tests/tests/ui/rbac/fail/missing_env.rs +18 -0
  49. package/contracts/macro-integration-tests/tests/ui/rbac/fail/missing_env.stderr +16 -0
  50. package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_address.rs +18 -0
  51. package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_address.stderr +24 -0
  52. package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_found.rs +18 -0
  53. package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_found.stderr +24 -0
  54. package/contracts/macro-integration-tests/tests/ui/rbac/pass/basic.rs +71 -0
  55. package/contracts/macro-integration-tests/tests/ui_rbac.rs +12 -0
  56. package/contracts/message-libs/blocked-message-lib/src/lib.rs +4 -4
  57. package/contracts/message-libs/uln-302/src/send_uln.rs +5 -5
  58. package/contracts/oapps/counter/src/counter.rs +6 -0
  59. package/contracts/oapps/oapp/src/oapp_sender.rs +3 -2
  60. package/contracts/oapps/oft/src/extensions/oft_fee.rs +5 -0
  61. package/contracts/oapps/oft/src/interfaces/mintable.rs +2 -2
  62. package/contracts/oapps/oft/src/oft.rs +5 -4
  63. package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +2 -2
  64. package/contracts/oapps/oft/src/tests/extensions/pausable.rs +2 -2
  65. package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +2 -2
  66. package/contracts/oapps/sac-manager/Cargo.toml +0 -1
  67. package/contracts/oapps/sac-manager/src/interfaces/mod.rs +3 -0
  68. package/contracts/oapps/sac-manager/src/interfaces/sac_admin_wrapper.rs +49 -0
  69. package/contracts/oapps/sac-manager/src/lib.rs +3 -3
  70. package/contracts/oapps/sac-manager/src/sac_manager.rs +45 -73
  71. package/contracts/oapps/sac-manager/src/storage.rs +2 -9
  72. package/contracts/oapps/sac-manager/src/tests/sac_manager/clawback.rs +8 -10
  73. package/contracts/oapps/sac-manager/src/tests/sac_manager/mint.rs +13 -18
  74. package/contracts/oapps/sac-manager/src/tests/sac_manager/mod.rs +0 -1
  75. package/contracts/oapps/sac-manager/src/tests/sac_manager/set_admin.rs +22 -12
  76. package/contracts/oapps/sac-manager/src/tests/sac_manager/set_authorized.rs +19 -9
  77. package/contracts/oapps/sac-manager/src/tests/sac_manager/test_helper.rs +27 -10
  78. package/contracts/oapps/sac-manager/src/tests/sac_manager/view_functions.rs +0 -15
  79. package/contracts/oapps/sac-manager/src/tests/test_helper.rs +19 -28
  80. package/contracts/upgrader/src/lib.rs +5 -2
  81. package/contracts/utils/src/auth.rs +6 -2
  82. package/contracts/utils/src/errors.rs +18 -0
  83. package/contracts/utils/src/lib.rs +1 -0
  84. package/contracts/utils/src/multisig.rs +5 -1
  85. package/contracts/utils/src/ownable.rs +1 -1
  86. package/contracts/utils/src/rbac.rs +428 -0
  87. package/contracts/utils/src/tests/auth.rs +2 -2
  88. package/contracts/utils/src/tests/mod.rs +1 -0
  89. package/contracts/utils/src/tests/multisig.rs +2 -2
  90. package/contracts/utils/src/tests/ownable.rs +4 -5
  91. package/contracts/utils/src/tests/rbac.rs +559 -0
  92. package/contracts/utils/src/tests/ttl_configurable.rs +5 -6
  93. package/contracts/utils/src/tests/upgradeable.rs +4 -5
  94. package/contracts/workers/worker/src/worker.rs +1 -1
  95. package/docs/layerzero-v2-on-stellar.md +46 -2
  96. package/package.json +3 -3
  97. package/sdk/.turbo/turbo-test.log +370 -372
  98. package/sdk/dist/generated/bml.d.ts +53 -3
  99. package/sdk/dist/generated/bml.js +27 -3
  100. package/sdk/dist/generated/counter.d.ts +84 -5
  101. package/sdk/dist/generated/counter.js +31 -4
  102. package/sdk/dist/generated/dvn.d.ts +55 -5
  103. package/sdk/dist/generated/dvn.js +28 -4
  104. package/sdk/dist/generated/dvn_fee_lib.d.ts +55 -5
  105. package/sdk/dist/generated/dvn_fee_lib.js +28 -4
  106. package/sdk/dist/generated/endpoint.d.ts +64 -15
  107. package/sdk/dist/generated/endpoint.js +32 -8
  108. package/sdk/dist/generated/executor.d.ts +55 -5
  109. package/sdk/dist/generated/executor.js +28 -4
  110. package/sdk/dist/generated/executor_fee_lib.d.ts +55 -5
  111. package/sdk/dist/generated/executor_fee_lib.js +28 -4
  112. package/sdk/dist/generated/executor_helper.d.ts +53 -3
  113. package/sdk/dist/generated/executor_helper.js +27 -3
  114. package/sdk/dist/generated/layerzero_view.d.ts +55 -5
  115. package/sdk/dist/generated/layerzero_view.js +28 -4
  116. package/sdk/dist/generated/oft.d.ts +84 -5
  117. package/sdk/dist/generated/oft.js +31 -4
  118. package/sdk/dist/generated/price_feed.d.ts +55 -5
  119. package/sdk/dist/generated/price_feed.js +28 -4
  120. package/sdk/dist/generated/sac_manager.d.ts +213 -666
  121. package/sdk/dist/generated/sac_manager.js +57 -238
  122. package/sdk/dist/generated/sml.d.ts +55 -5
  123. package/sdk/dist/generated/sml.js +28 -4
  124. package/sdk/dist/generated/treasury.d.ts +55 -5
  125. package/sdk/dist/generated/treasury.js +28 -4
  126. package/sdk/dist/generated/uln302.d.ts +55 -5
  127. package/sdk/dist/generated/uln302.js +28 -4
  128. package/sdk/dist/generated/upgrader.d.ts +53 -3
  129. package/sdk/dist/generated/upgrader.js +27 -3
  130. package/sdk/package.json +1 -1
  131. package/sdk/test/oft-sml.test.ts +10 -9
  132. package/sdk/test/{sac-manager-redistribution.test.ts → sac-manager.test.ts} +49 -25
  133. package/contracts/endpoint-v2/src/tests/messaging_channel/lazy_inbound_nonce.rs +0 -39
  134. package/contracts/oapps/sac-manager/src/errors.rs +0 -14
  135. package/contracts/oapps/sac-manager/src/tests/sac_manager/set_minter.rs +0 -69
package/Cargo.lock CHANGED
@@ -1755,9 +1755,9 @@ dependencies = [
1755
1755
 
1756
1756
  [[package]]
1757
1757
  name = "soroban-ledger-snapshot"
1758
- version = "25.1.0"
1758
+ version = "25.1.1"
1759
1759
  source = "registry+https://github.com/rust-lang/crates.io-index"
1760
- checksum = "99c5285c83e7a5581879b7a65033eae53b24ac9689975aa6887f1d8ee3e941c9"
1760
+ checksum = "66d569a1315f05216d024653ad87541aa15d3ff26dad9f8a98719cb53ccf2bf3"
1761
1761
  dependencies = [
1762
1762
  "serde",
1763
1763
  "serde_json",
@@ -1769,9 +1769,9 @@ dependencies = [
1769
1769
 
1770
1770
  [[package]]
1771
1771
  name = "soroban-sdk"
1772
- version = "25.1.0"
1772
+ version = "25.1.1"
1773
1773
  source = "registry+https://github.com/rust-lang/crates.io-index"
1774
- checksum = "b1262aa83e99a0fb3e8cd56d6e5ca4c28ac4f9871ac7173f65301a8b9a12c20f"
1774
+ checksum = "add8d19cfd2c9941bbdc7c8223c3cf9d7ff9af4554ba3bd4ae93e16b19b08aea"
1775
1775
  dependencies = [
1776
1776
  "arbitrary",
1777
1777
  "bytes-lit",
@@ -1793,9 +1793,9 @@ dependencies = [
1793
1793
 
1794
1794
  [[package]]
1795
1795
  name = "soroban-sdk-macros"
1796
- version = "25.1.0"
1796
+ version = "25.1.1"
1797
1797
  source = "registry+https://github.com/rust-lang/crates.io-index"
1798
- checksum = "93b62c526917a1e77b6dce3cd841b6c271f0fff344ea93ad92a8c45afe8051b6"
1798
+ checksum = "2a0107e34575ec704ce29407695462e79e6b0e13ce7af6431b2f15c313e34464"
1799
1799
  dependencies = [
1800
1800
  "darling 0.20.11",
1801
1801
  "heck 0.5.0",
@@ -1813,9 +1813,9 @@ dependencies = [
1813
1813
 
1814
1814
  [[package]]
1815
1815
  name = "soroban-spec"
1816
- version = "25.1.0"
1816
+ version = "25.1.1"
1817
1817
  source = "registry+https://github.com/rust-lang/crates.io-index"
1818
- checksum = "0186c943a78de7038ce7eee478f521f7a7665440101ae0d24b4a59833fb6d833"
1818
+ checksum = "53a1c9f6ccc6aa78518545e3cf542bd26f11d9085328a2e1c06c90514733fe15"
1819
1819
  dependencies = [
1820
1820
  "base64 0.22.1",
1821
1821
  "stellar-xdr",
@@ -1825,9 +1825,9 @@ dependencies = [
1825
1825
 
1826
1826
  [[package]]
1827
1827
  name = "soroban-spec-rust"
1828
- version = "25.1.0"
1828
+ version = "25.1.1"
1829
1829
  source = "registry+https://github.com/rust-lang/crates.io-index"
1830
- checksum = "7a948196ed0633be3a4125e0c7a4fc0bb6337942e538813b1f171331738f9058"
1830
+ checksum = "e8247d3c6256b544b2461606c6892351bb22978d751e07c1aea744377053d852"
1831
1831
  dependencies = [
1832
1832
  "prettyplease",
1833
1833
  "proc-macro2",
package/Cargo.toml CHANGED
@@ -14,7 +14,7 @@ license = "MIT"
14
14
  version = "0.0.1"
15
15
 
16
16
  [workspace.dependencies]
17
- soroban-sdk = { version = "25.1.0", features = ["hazmat-address", "hazmat-crypto"] }
17
+ soroban-sdk = { version = "25.1.1", features = ["hazmat-address", "hazmat-crypto"] }
18
18
  soroban-spec-typescript = "25.1.0" # used in tools/ts-bindings-gen
19
19
 
20
20
  # Third-party dependencies (production)
@@ -27,14 +27,14 @@ pub fn generate_ownable_impl(input: TokenStream) -> TokenStream {
27
27
  quote! {
28
28
  #item_struct
29
29
 
30
- use utils::{auth::Auth as _, option_ext::OptionExt as _, ownable::{Ownable as _, OwnableInitializer as _}};
30
+ use utils::{auth::Auth as _, ownable::{Ownable as _, OwnableInitializer as _}};
31
31
 
32
32
  impl utils::ownable::OwnableInitializer for #name {}
33
33
 
34
34
  #[common_macros::contract_impl]
35
35
  impl utils::auth::Auth for #name {
36
- fn authorizer(env: &soroban_sdk::Env) -> soroban_sdk::Address {
37
- <Self as utils::ownable::Ownable>::owner(env).unwrap_or_panic(env, utils::errors::OwnableError::OwnerNotSet)
36
+ fn authorizer(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
37
+ <Self as utils::ownable::Ownable>::owner(env)
38
38
  }
39
39
  }
40
40
 
@@ -63,8 +63,8 @@ pub fn generate_multisig_impl(input: TokenStream) -> TokenStream {
63
63
 
64
64
  #[common_macros::contract_impl]
65
65
  impl utils::auth::Auth for #name {
66
- fn authorizer(env: &soroban_sdk::Env) -> soroban_sdk::Address {
67
- env.current_contract_address()
66
+ fn authorizer(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
67
+ Some(env.current_contract_address())
68
68
  }
69
69
  }
70
70
 
@@ -7,6 +7,8 @@
7
7
  //! - [`lz_contract`] - Wrapper macro combining common LayerZero contract attributes
8
8
  //! - [`multisig`] - MultiSig trait implementation macro
9
9
  //! - [`only_auth`] - Auth-based access control attribute macro
10
+ //! - [`only_role`] - RBAC role check with auth attribute macro
11
+ //! - [`has_role`] - RBAC role check attribute macro
10
12
  //! - [`ownable`] - Ownable trait implementation macro
11
13
  //! - [`storage`] - Storage enum to API macro
12
14
  //! - [`ttl_configurable`] - TTL configuration with freeze support
@@ -20,6 +22,7 @@ mod auth;
20
22
  mod contract_ttl;
21
23
  mod error;
22
24
  mod lz_contract;
25
+ mod rbac;
23
26
  mod storage;
24
27
  mod ttl_configurable;
25
28
  mod ttl_extendable;
@@ -232,6 +235,72 @@ pub fn only_auth(_attr: TokenStream, item: TokenStream) -> TokenStream {
232
235
  auth::prepend_only_auth_check(item.into()).into()
233
236
  }
234
237
 
238
+ // ============================================================================
239
+ // RBAC Macros
240
+ // ============================================================================
241
+
242
+ /// Checks that the given account has the specified role.
243
+ ///
244
+ /// Injects a role check at the start of the function. Panics with
245
+ /// `RbacError::Unauthorized` if the account does not have the role (aligns with OpenZeppelin).
246
+ ///
247
+ /// # Requirements
248
+ /// - The function must have an `Env` parameter
249
+ /// - The function must have a parameter matching the first macro arg (of type `Address` or `&Address`)
250
+ /// - The contract must use `utils::rbac` (e.g. `RbacStorage` or `RoleBasedAccessControl`)
251
+ ///
252
+ /// # Example
253
+ /// ```ignore
254
+ /// #[has_role(caller, "minter")]
255
+ /// pub fn mint(env: Env, caller: Address, amount: i128) { ... }
256
+ ///
257
+ /// // Or with a &str constant:
258
+ /// const MINTER_ROLE: &str = "minter";
259
+ /// #[has_role(caller, MINTER_ROLE)]
260
+ /// pub fn mint(env: Env, caller: Address, amount: i128) { ... }
261
+ /// ```
262
+ ///
263
+ /// # Generated code
264
+ /// ```ignore
265
+ /// pub fn mint(env: Env, caller: Address, amount: i128) {
266
+ /// utils::rbac::ensure_role(&env, &soroban_sdk::Symbol::new(&env, "minter"), &caller);
267
+ /// // Original function body
268
+ /// }
269
+ /// ```
270
+ #[proc_macro_attribute]
271
+ pub fn has_role(attr: TokenStream, item: TokenStream) -> TokenStream {
272
+ rbac::generate_role_check(attr.into(), item.into(), false).into()
273
+ }
274
+
275
+ /// Checks that the given account has the specified role and requires auth.
276
+ ///
277
+ /// Same as `#[has_role]` but also calls `account.require_auth()` to ensure
278
+ /// the caller has authorized the transaction.
279
+ ///
280
+ /// # Requirements
281
+ /// Same as `#[has_role]`.
282
+ ///
283
+ /// # Example
284
+ /// ```ignore
285
+ /// #[only_role(caller, "minter")]
286
+ /// pub fn mint(env: Env, caller: Address, amount: i128) { ... }
287
+ ///
288
+ /// // Or with a &str constant: #[only_role(caller, MINTER_ROLE)]
289
+ /// ```
290
+ ///
291
+ /// # Generated code
292
+ /// ```ignore
293
+ /// pub fn mint(env: Env, caller: Address, amount: i128) {
294
+ /// utils::rbac::ensure_role(&env, &soroban_sdk::Symbol::new(&env, "minter"), &caller);
295
+ /// caller.require_auth();
296
+ /// // Original function body
297
+ /// }
298
+ /// ```
299
+ #[proc_macro_attribute]
300
+ pub fn only_role(attr: TokenStream, item: TokenStream) -> TokenStream {
301
+ rbac::generate_role_check(attr.into(), item.into(), true).into()
302
+ }
303
+
235
304
  // ============================================================================
236
305
  // TTL Configuration Macro
237
306
  // ============================================================================
@@ -0,0 +1,90 @@
1
+ //! RBAC attribute macros for Stellar contracts.
2
+ //!
3
+ //! Provides `#[has_role]` and `#[only_role]` for role-based access control,
4
+ //! delegating to `utils::rbac::ensure_role`.
5
+
6
+ use crate::utils;
7
+ use proc_macro2::TokenStream;
8
+ use quote::{quote, ToTokens};
9
+ use syn::parse_quote;
10
+ use syn::{
11
+ parse::{Parse, ParseStream},
12
+ Expr, FnArg, Ident, ItemFn, Pat, Token, Type,
13
+ };
14
+
15
+ /// Helper that generates the role check for both `has_role` and `only_role`.
16
+ /// If `require_auth` is true, also injects `account.require_auth()`.
17
+ pub fn generate_role_check(args: TokenStream, input: TokenStream, require_auth: bool) -> TokenStream {
18
+ let HasRoleArgs { param, role } =
19
+ syn::parse2(args).unwrap_or_else(|e| panic!("failed to parse has_role/only_role args: {}", e));
20
+ let mut input_fn: ItemFn = syn::parse2(input).unwrap_or_else(|e| panic!("failed to parse function: {}", e));
21
+
22
+ let is_address_ref = validate_address_type(&input_fn, &param);
23
+ let param_ref = if is_address_ref { quote!(#param) } else { quote!(&#param) };
24
+
25
+ let env_param = utils::expect_env_param(&input_fn.sig.inputs);
26
+ let env_ref = env_param.as_ref_tokens();
27
+
28
+ // Insert the role check at the beginning of the function body
29
+ input_fn.block.stmts.insert(
30
+ 0,
31
+ parse_quote!(utils::rbac::ensure_role(#env_ref, &soroban_sdk::Symbol::new(#env_ref, #role), #param_ref);),
32
+ );
33
+ if require_auth {
34
+ input_fn.block.stmts.insert(1, parse_quote!(#param.require_auth();));
35
+ }
36
+ input_fn.into_token_stream()
37
+ }
38
+
39
+ struct HasRoleArgs {
40
+ param: Ident,
41
+ role: Expr,
42
+ }
43
+
44
+ impl Parse for HasRoleArgs {
45
+ fn parse(input: ParseStream) -> syn::Result<Self> {
46
+ // Parse the parameter name (the account identifier to check)
47
+ let param: Ident = input.parse()?;
48
+ // Expect a comma separator between param and role
49
+ input.parse::<Token![,]>()?;
50
+ // Parse the role expression (e.g., a string literal or constant)
51
+ let role: Expr = input.parse()?;
52
+ Ok(HasRoleArgs { param, role })
53
+ }
54
+ }
55
+
56
+ /// Looks up `param_name` in the function signature and validates that its type
57
+ /// is `Address` or `&Address`. Returns `true` when the parameter is a reference,
58
+ /// so the caller knows whether an extra `&` is needed when forwarding it.
59
+ ///
60
+ /// Panics at macro-expansion time if the parameter doesn't exist.
61
+ fn validate_address_type(func: &ItemFn, param_name: &Ident) -> bool {
62
+ for arg in &func.sig.inputs {
63
+ let FnArg::Typed(pat_type) = arg else { continue };
64
+ let Pat::Ident(pat_ident) = &*pat_type.pat else { continue };
65
+ if pat_ident.ident != *param_name {
66
+ continue;
67
+ }
68
+ return match &*pat_type.ty {
69
+ Type::Reference(r) => {
70
+ assert_is_address(&r.elem, param_name);
71
+ true
72
+ }
73
+ ty => {
74
+ assert_is_address(ty, param_name);
75
+ false
76
+ }
77
+ };
78
+ }
79
+ panic!("Parameter `{param_name}` not found in function signature");
80
+ }
81
+
82
+ /// Asserts that the type path resolves to `Address`, panicking otherwise.
83
+ fn assert_is_address(ty: &Type, param_name: &Ident) {
84
+ let Type::Path(tp) = ty else {
85
+ panic!("Parameter `{param_name}` must be of type `Address` or `&Address`");
86
+ };
87
+ if tp.path.segments.last().is_none_or(|s| s.ident != "Address") {
88
+ panic!("Parameter `{param_name}` must be of type `Address` or `&Address`");
89
+ }
90
+ }
@@ -119,7 +119,7 @@ fn gen_accessor_methods(enum_name: &Ident, variant: &Variant) -> TokenStream {
119
119
 
120
120
  // Getter: returns the value directly (with default) or wrapped in Option.
121
121
  let (ret_type, ret_expr) = match &config.default_value {
122
- Some(default) => (quote! { #value_type }, quote! { value.unwrap_or(#default) }),
122
+ Some(default) => (quote! { #value_type }, quote! { value.unwrap_or_else(|| #default) }),
123
123
  None => (quote! { Option<#value_type> }, quote! { value }),
124
124
  };
125
125
  let ttl_on_get = extend_ttl.as_ref().map(|call| quote! { if value.is_some() { #call } });
@@ -131,10 +131,12 @@ fn gen_accessor_methods(enum_name: &Ident, variant: &Variant) -> TokenStream {
131
131
  };
132
132
 
133
133
  // TTL extender method — only for persistent/temporary storage (instance has no per-key TTL).
134
- let ttl_extender_method = (config.kind != StorageKind::Instance).then(|| quote! {
135
- pub fn #ttl_extender(#params, threshold: u32, extend_to: u32) {
136
- let key = #key;
137
- #accessor.extend_ttl(&key, threshold, extend_to);
134
+ let ttl_extender_method = (config.kind != StorageKind::Instance).then(|| {
135
+ quote! {
136
+ pub fn #ttl_extender(#params, threshold: u32, extend_to: u32) {
137
+ let key = #key;
138
+ #accessor.extend_ttl(&key, threshold, extend_to);
139
+ }
138
140
  }
139
141
  });
140
142
 
@@ -22,8 +22,10 @@ fn snapshot_generated_lz_contract_code() {
22
22
  &syn::parse2::<syn::File>(multisig_upgradeable_result).expect("failed to parse generated code"),
23
23
  );
24
24
 
25
- let upgradeable_no_migration_result =
26
- crate::lz_contract::generate_lz_contract(quote! { upgradeable(no_migration) }, quote! { pub struct MyContract; });
25
+ let upgradeable_no_migration_result = crate::lz_contract::generate_lz_contract(
26
+ quote! { upgradeable(no_migration) },
27
+ quote! { pub struct MyContract; },
28
+ );
27
29
  let upgradeable_no_migration_formatted = prettyplease::unparse(
28
30
  &syn::parse2::<syn::File>(upgradeable_no_migration_result).expect("failed to parse generated code"),
29
31
  );
@@ -45,11 +47,7 @@ fn test_lz_contract_invalid_config_table_driven() {
45
47
  let input = quote! { pub struct MyContract; };
46
48
 
47
49
  let cases: Vec<(&str, TokenStream, &str)> = vec![
48
- (
49
- "unknown option",
50
- quote! { not_a_real_option },
51
- "expected one of `upgradeable`, `multisig`",
52
- ),
50
+ ("unknown option", quote! { not_a_real_option }, "expected one of `upgradeable`, `multisig`"),
53
51
  ("invalid attr syntax", quote! { 123 }, "failed to parse lz_contract config"),
54
52
  ("upgradeable(bad_inner)", quote! { upgradeable(not_migration) }, "expected `no_migration`"),
55
53
  (
@@ -2,6 +2,7 @@ mod auth;
2
2
  mod contract_ttl;
3
3
  mod error;
4
4
  mod lz_contract;
5
+ mod rbac;
5
6
  mod storage;
6
7
  mod test_helpers;
7
8
  mod ttl_configurable;