@layerzerolabs/protocol-stellar-v2 0.2.29 → 0.2.30

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 (205) hide show
  1. package/.turbo/turbo-build.log +371 -321
  2. package/.turbo/turbo-lint.log +211 -202
  3. package/.turbo/turbo-test.log +1766 -1673
  4. package/Cargo.lock +11 -1
  5. package/contracts/common-macros/src/lib.rs +0 -2
  6. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +1 -0
  7. package/contracts/endpoint-v2/src/messaging_channel.rs +32 -3
  8. package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +1 -1
  9. package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +1 -1
  10. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +6 -6
  11. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_payload_hash.rs +1 -1
  12. package/contracts/endpoint-v2/src/tests/messaging_channel/outbound.rs +16 -10
  13. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +10 -10
  14. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +3 -3
  15. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +4 -3
  16. package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +1 -57
  17. package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_missing_internal.stderr +0 -30
  18. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -3
  19. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +6 -4
  20. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -3
  21. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -3
  22. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_auth_trait.stderr +0 -30
  23. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_upgradeable_internal.stderr +0 -30
  24. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/basic.rs +0 -2
  25. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/multisig_contract.rs +0 -2
  26. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/no_migration.rs +0 -2
  27. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/no_user_contractimpl.rs +1 -3
  28. package/contracts/message-libs/message-lib-common/src/packet_codec_v1.rs +3 -6
  29. package/contracts/message-libs/message-lib-common/src/tests/worker_options/extract_type_3_options.rs +10 -0
  30. package/contracts/message-libs/message-lib-common/src/worker_options.rs +6 -2
  31. package/contracts/message-libs/treasury/src/interfaces/zro_fee_lib.rs +3 -3
  32. package/contracts/message-libs/treasury/src/lib.rs +2 -1
  33. package/contracts/message-libs/treasury/src/tests/setup.rs +1 -1
  34. package/contracts/message-libs/treasury/src/treasury.rs +5 -2
  35. package/contracts/message-libs/uln-302/src/errors.rs +2 -0
  36. package/contracts/message-libs/uln-302/src/events.rs +3 -3
  37. package/contracts/message-libs/uln-302/src/interfaces/receive_uln.rs +8 -0
  38. package/contracts/message-libs/uln-302/src/lib.rs +2 -1
  39. package/contracts/message-libs/uln-302/src/receive_uln.rs +16 -13
  40. package/contracts/message-libs/uln-302/src/send_uln.rs +51 -24
  41. package/contracts/message-libs/uln-302/src/storage.rs +2 -2
  42. package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +45 -1
  43. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verifiable.rs +63 -0
  44. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +47 -2
  45. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +50 -1
  46. package/contracts/message-libs/uln-302/src/uln302.rs +0 -8
  47. package/contracts/oapps/counter/Cargo.toml +4 -4
  48. package/contracts/oapps/counter/integration_tests/setup_uln.rs +22 -2
  49. package/contracts/oapps/counter/src/counter.rs +8 -8
  50. package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +33 -10
  51. package/contracts/oapps/oapp/src/lib.rs +6 -2
  52. package/contracts/oapps/oapp/src/oapp_core.rs +49 -24
  53. package/contracts/oapps/oapp/src/oapp_options_type3.rs +21 -14
  54. package/contracts/oapps/oapp/src/oapp_receiver.rs +17 -16
  55. package/contracts/oapps/oapp/src/oapp_sender.rs +66 -15
  56. package/contracts/oapps/oapp/src/tests/oapp_core.rs +5 -5
  57. package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +18 -18
  58. package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +4 -4
  59. package/contracts/oapps/oapp/src/tests/oapp_sender.rs +3 -3
  60. package/contracts/oapps/oapp-macros/Cargo.toml +0 -1
  61. package/contracts/oapps/oapp-macros/src/generators.rs +87 -46
  62. package/contracts/oapps/oapp-macros/src/lib.rs +3 -61
  63. package/contracts/oapps/oapp-macros/src/tests/oapp.rs +9 -23
  64. package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +15 -11
  65. package/contracts/oapps/oft/Cargo.toml +1 -1
  66. package/contracts/oapps/oft/integration-tests/extensions/test_oft_fee.rs +3 -3
  67. package/contracts/oapps/oft/integration-tests/extensions/test_pausable.rs +4 -4
  68. package/contracts/oapps/oft/integration-tests/extensions/test_rate_limiter.rs +144 -8
  69. package/contracts/oapps/oft/integration-tests/setup.rs +4 -2
  70. package/contracts/oapps/oft/integration-tests/utils.rs +25 -11
  71. package/contracts/oapps/oft/src/extensions/oft_fee.rs +65 -63
  72. package/contracts/oapps/oft/src/extensions/pausable.rs +2 -3
  73. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +22 -5
  74. package/contracts/oapps/oft/src/interfaces/mint_burnable.rs +18 -0
  75. package/contracts/oapps/oft/src/interfaces/mod.rs +3 -0
  76. package/contracts/oapps/oft/src/lib.rs +4 -2
  77. package/contracts/oapps/oft/src/oft.rs +35 -36
  78. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +13 -9
  79. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +14 -9
  80. package/contracts/oapps/oft/src/oft_types/mod.rs +14 -12
  81. package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +28 -20
  82. package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +136 -2
  83. package/contracts/oapps/oft/src/tests/oft_types/lock_unlock.rs +12 -8
  84. package/contracts/oapps/oft-core/integration-tests/setup.rs +8 -9
  85. package/contracts/oapps/oft-core/integration-tests/test_with_sml.rs +7 -6
  86. package/contracts/oapps/oft-core/integration-tests/utils.rs +5 -4
  87. package/contracts/oapps/oft-core/src/codec/oft_compose_msg_codec.rs +2 -2
  88. package/contracts/oapps/oft-core/src/codec/oft_msg_codec.rs +33 -37
  89. package/contracts/oapps/oft-core/src/errors.rs +2 -1
  90. package/contracts/oapps/oft-core/src/events.rs +6 -0
  91. package/contracts/oapps/oft-core/src/lib.rs +8 -4
  92. package/contracts/oapps/oft-core/src/oft_core.rs +205 -148
  93. package/contracts/oapps/oft-core/src/storage.rs +4 -2
  94. package/contracts/oapps/oft-core/src/tests/test_decimals.rs +2 -2
  95. package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +6 -6
  96. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +7 -6
  97. package/contracts/oapps/oft-core/src/tests/test_oft_msg_codec.rs +11 -82
  98. package/contracts/oapps/oft-core/src/tests/test_quote_oft.rs +13 -13
  99. package/contracts/oapps/oft-core/src/tests/test_quote_send.rs +1 -1
  100. package/contracts/oapps/oft-core/src/tests/test_resolve_address.rs +2 -2
  101. package/contracts/oapps/oft-core/src/tests/test_send.rs +22 -22
  102. package/contracts/oapps/oft-core/src/tests/test_utils.rs +20 -22
  103. package/contracts/oapps/oft-core/src/utils.rs +12 -8
  104. package/contracts/sac-manager/Cargo.toml +25 -0
  105. package/contracts/sac-manager/src/errors.rs +18 -0
  106. package/contracts/sac-manager/src/extensions/mod.rs +6 -0
  107. package/contracts/sac-manager/src/extensions/redistribution.rs +109 -0
  108. package/contracts/sac-manager/src/extensions/supply_control/mod.rs +488 -0
  109. package/contracts/sac-manager/src/extensions/supply_control/rate_limit.rs +126 -0
  110. package/contracts/sac-manager/src/interfaces/mod.rs +3 -0
  111. package/contracts/sac-manager/src/interfaces/sac_manager.rs +52 -0
  112. package/contracts/sac-manager/src/lib.rs +23 -0
  113. package/contracts/sac-manager/src/sac_manager.rs +193 -0
  114. package/contracts/sac-manager/src/storage.rs +20 -0
  115. package/contracts/sac-manager/src/tests/mod.rs +14 -0
  116. package/contracts/sac-manager/src/tests/redistribution/mod.rs +1 -0
  117. package/contracts/sac-manager/src/tests/redistribution/redistribute_funds.rs +82 -0
  118. package/contracts/sac-manager/src/tests/sac_manager/admin_mint.rs +206 -0
  119. package/contracts/sac-manager/src/tests/sac_manager/burn.rs +215 -0
  120. package/contracts/sac-manager/src/tests/sac_manager/clawback.rs +209 -0
  121. package/contracts/sac-manager/src/tests/sac_manager/mint.rs +252 -0
  122. package/contracts/sac-manager/src/tests/sac_manager/mod.rs +9 -0
  123. package/contracts/sac-manager/src/tests/sac_manager/set_admin.rs +36 -0
  124. package/contracts/sac-manager/src/tests/sac_manager/set_authorized.rs +43 -0
  125. package/contracts/sac-manager/src/tests/sac_manager/set_oft_address.rs +47 -0
  126. package/contracts/sac-manager/src/tests/sac_manager/test_helper.rs +75 -0
  127. package/contracts/sac-manager/src/tests/sac_manager/view_functions.rs +60 -0
  128. package/contracts/sac-manager/src/tests/supply_control/enumerable_set.rs +256 -0
  129. package/contracts/sac-manager/src/tests/supply_control/mod.rs +8 -0
  130. package/contracts/sac-manager/src/tests/supply_control/refill.rs +90 -0
  131. package/contracts/sac-manager/src/tests/supply_control/set_mint_whitelist.rs +245 -0
  132. package/contracts/sac-manager/src/tests/supply_control/set_supply_controller.rs +267 -0
  133. package/contracts/sac-manager/src/tests/supply_control/set_supply_controller_manager.rs +122 -0
  134. package/contracts/sac-manager/src/tests/supply_control/test_helper.rs +38 -0
  135. package/contracts/sac-manager/src/tests/supply_control/update_allow_any_mint_burn.rs +114 -0
  136. package/contracts/sac-manager/src/tests/supply_control/update_limit_config.rs +257 -0
  137. package/contracts/sac-manager/src/tests/test_helper.rs +190 -0
  138. package/contracts/upgrader/src/lib.rs +2 -1
  139. package/contracts/utils/src/errors.rs +0 -1
  140. package/contracts/utils/src/tests/upgradeable.rs +0 -66
  141. package/contracts/utils/src/upgradeable.rs +0 -18
  142. package/contracts/workers/dvn/src/dvn.rs +2 -2
  143. package/contracts/workers/dvn/src/interfaces/dvn.rs +2 -2
  144. package/contracts/workers/dvn/src/lib.rs +2 -1
  145. package/contracts/workers/dvn-fee-lib/src/lib.rs +3 -1
  146. package/contracts/workers/executor/src/auth.rs +42 -26
  147. package/contracts/workers/executor/src/executor.rs +28 -3
  148. package/contracts/workers/executor/src/lib.rs +4 -2
  149. package/contracts/workers/executor/src/storage.rs +21 -1
  150. package/contracts/workers/executor/src/tests/auth.rs +64 -20
  151. package/contracts/workers/executor/src/tests/executor.rs +1 -1
  152. package/contracts/workers/executor/src/tests/setup.rs +18 -0
  153. package/contracts/workers/executor-fee-lib/src/lib.rs +4 -1
  154. package/contracts/workers/executor-helper/src/executor_helper.rs +24 -10
  155. package/contracts/workers/executor-helper/src/tests/setup.rs +147 -34
  156. package/contracts/workers/price-feed/src/lib.rs +3 -1
  157. package/contracts/workers/worker/src/lib.rs +2 -1
  158. package/contracts/workers/worker/src/worker.rs +31 -17
  159. package/docs/oapp-guide.md +17 -8
  160. package/docs/oft-guide.md +3 -3
  161. package/package.json +3 -3
  162. package/sdk/.turbo/turbo-test.log +512 -351
  163. package/sdk/dist/generated/bml.d.ts +3 -9
  164. package/sdk/dist/generated/bml.js +6 -7
  165. package/sdk/dist/generated/counter.d.ts +22 -28
  166. package/sdk/dist/generated/counter.js +11 -12
  167. package/sdk/dist/generated/dvn.d.ts +36 -54
  168. package/sdk/dist/generated/dvn.js +10 -15
  169. package/sdk/dist/generated/dvn_fee_lib.d.ts +3 -21
  170. package/sdk/dist/generated/dvn_fee_lib.js +6 -11
  171. package/sdk/dist/generated/endpoint.d.ts +3 -9
  172. package/sdk/dist/generated/endpoint.js +6 -7
  173. package/sdk/dist/generated/executor.d.ts +80 -54
  174. package/sdk/dist/generated/executor.js +16 -16
  175. package/sdk/dist/generated/executor_fee_lib.d.ts +3 -21
  176. package/sdk/dist/generated/executor_fee_lib.js +6 -11
  177. package/sdk/dist/generated/executor_helper.d.ts +36 -42
  178. package/sdk/dist/generated/executor_helper.js +9 -10
  179. package/sdk/dist/generated/layerzero_view.d.ts +20 -32
  180. package/sdk/dist/generated/layerzero_view.js +25 -26
  181. package/sdk/dist/generated/oft.d.ts +147 -79
  182. package/sdk/dist/generated/oft.js +47 -54
  183. package/sdk/dist/generated/price_feed.d.ts +20 -38
  184. package/sdk/dist/generated/price_feed.js +15 -20
  185. package/sdk/dist/generated/sac_manager.d.ts +1309 -0
  186. package/sdk/dist/generated/sac_manager.js +484 -0
  187. package/sdk/dist/generated/sml.d.ts +3 -9
  188. package/sdk/dist/generated/sml.js +6 -7
  189. package/sdk/dist/generated/treasury.d.ts +3 -9
  190. package/sdk/dist/generated/treasury.js +8 -9
  191. package/sdk/dist/generated/uln302.d.ts +20 -20
  192. package/sdk/dist/generated/uln302.js +25 -22
  193. package/sdk/dist/generated/upgrader.d.ts +3 -9
  194. package/sdk/dist/generated/upgrader.js +6 -7
  195. package/sdk/dist/index.d.ts +1 -0
  196. package/sdk/dist/index.js +1 -0
  197. package/sdk/package.json +1 -1
  198. package/sdk/src/index.ts +1 -0
  199. package/sdk/test/oft-sml.test.ts +7 -5
  200. package/sdk/test/sac-manager-redistribution.test.ts +578 -0
  201. package/sdk/test/suites/globalSetup.ts +11 -6
  202. package/sdk/test/test_data/test_upgradeable_dvn.wasm +0 -0
  203. package/sdk/test/upgrader.test.ts +75 -202
  204. package/sdk/test/utils.ts +40 -0
  205. package/tools/ts-bindings-gen/src/main.rs +1 -0
@@ -0,0 +1,206 @@
1
+ //! authorized_mint Integration Tests
2
+ //!
3
+ //! Core mint logic (supply control, redistribution, events) is tested via
4
+ //! MintBurnable tests in `mint.rs`. These tests focus on authorized_mint-specific
5
+ //! behavior: auth, owner fallback, and supply controllers calling directly.
6
+
7
+ use super::test_helper::{mock_authorized_mint_auth, mock_set_authorized_auth, mock_set_supply_controller_auth};
8
+ use crate::errors::SacManagerError;
9
+ use crate::extensions::redistribution::RedistributeFunds;
10
+ use crate::extensions::supply_control::SupplyIncreased;
11
+ use crate::extensions::supply_control::{LimitConfig, SupplyControlError, SupplyControllerConfig};
12
+ use crate::tests::test_helper::TestSetup;
13
+ use soroban_sdk::{testutils::IssuerFlags, Vec};
14
+ use utils::testing_utils::{assert_contains_event, assert_contains_events};
15
+
16
+ // =========================================================================
17
+ // authorized_mint Tests (without Supply Control — owner only)
18
+ // =========================================================================
19
+
20
+ #[test]
21
+ fn test_authorized_mint_by_owner() {
22
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
23
+ let recipient = setup.generate_address();
24
+
25
+ mock_authorized_mint_auth(&setup, &setup.owner, &recipient, 1000_i128);
26
+ setup.sac_manager_client.authorized_mint(&setup.owner, &recipient, &1000);
27
+ assert_eq!(setup.sac_client.balance(&recipient), 1000);
28
+ }
29
+
30
+ #[test]
31
+ fn test_authorized_mint_redistributes_when_recipient_blacklisted() {
32
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_redistribution_enabled().build();
33
+ let blacklisted_recipient = setup.generate_address();
34
+
35
+ // Enable issuer flags required for blacklist and clawback behavior in SAC tests.
36
+ setup.sac_contract.issuer().set_flag(IssuerFlags::RevocableFlag);
37
+ setup.sac_contract.issuer().set_flag(IssuerFlags::ClawbackEnabledFlag);
38
+
39
+ mock_set_authorized_auth(&setup, &blacklisted_recipient, false);
40
+ setup.sac_manager_client.set_authorized(&blacklisted_recipient, &false);
41
+ assert!(!setup.sac_client.authorized(&blacklisted_recipient));
42
+
43
+ let owner_balance_before = setup.sac_client.balance(&setup.owner);
44
+ let blacklisted_balance_before = setup.sac_client.balance(&blacklisted_recipient);
45
+
46
+ // authorized_mint resolves recipient to owner when target is blacklisted (redistribution path).
47
+ mock_authorized_mint_auth(&setup, &setup.owner, &blacklisted_recipient, 700_i128);
48
+ setup.sac_manager_client.authorized_mint(&setup.owner, &blacklisted_recipient, &700);
49
+
50
+ // No SupplyIncreased when supply control is off; only RedistributeFunds is emitted.
51
+ let expected = RedistributeFunds { user: blacklisted_recipient.clone(), amount: 700 };
52
+ assert_contains_event(&setup.env, &setup.sac_manager, expected);
53
+
54
+ assert_eq!(setup.sac_client.balance(&blacklisted_recipient), blacklisted_balance_before);
55
+ assert_eq!(setup.sac_client.balance(&setup.owner), owner_balance_before + 700);
56
+ }
57
+
58
+ #[test]
59
+ fn test_authorized_mint_by_non_owner_fails_without_supply_control() {
60
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
61
+ let recipient = setup.generate_address();
62
+ let random = setup.generate_address();
63
+
64
+ // Supply control is off — only owner can call
65
+ mock_authorized_mint_auth(&setup, &random, &recipient, 1000_i128);
66
+ let result = setup.sac_manager_client.try_authorized_mint(&random, &recipient, &1000);
67
+ assert_eq!(result.err().unwrap().unwrap(), SacManagerError::Unauthorized.into());
68
+ }
69
+
70
+ // =========================================================================
71
+ // authorized_mint Tests (with Supply Control)
72
+ // =========================================================================
73
+
74
+ #[test]
75
+ fn test_authorized_mint_by_supply_controller() {
76
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
77
+ let recipient = setup.generate_address();
78
+ let controller = setup.generate_address();
79
+
80
+ let config = SupplyControllerConfig {
81
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
82
+ allow_any_mint_burn: true,
83
+ whitelist_addresses: Vec::new(&setup.env),
84
+ };
85
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &controller, &Some(config.clone()));
86
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &controller, &Some(config.clone()));
87
+
88
+ mock_authorized_mint_auth(&setup, &controller, &recipient, 1000_i128);
89
+ setup.sac_manager_client.authorized_mint(&controller, &recipient, &1000);
90
+ assert_eq!(setup.sac_client.balance(&recipient), 1000);
91
+ }
92
+
93
+ #[test]
94
+ fn test_authorized_mint_by_owner_fails_with_supply_control_without_config() {
95
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
96
+ let recipient = setup.generate_address();
97
+
98
+ // Owner is not auto-authorized when supply control is enabled and has no controller config.
99
+ mock_authorized_mint_auth(&setup, &setup.owner, &recipient, 1000_i128);
100
+ let result = setup.sac_manager_client.try_authorized_mint(&setup.owner, &recipient, &1000);
101
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::NotFound.into());
102
+ }
103
+
104
+ #[test]
105
+ fn test_authorized_mint_redistributes_with_supply_control_enabled() {
106
+ let setup = TestSetup::new()
107
+ .with_manager_as_sac_admin()
108
+ .with_supply_control_enabled()
109
+ .with_redistribution_enabled()
110
+ .build();
111
+ let controller = setup.generate_address();
112
+ let blacklisted_recipient = setup.generate_address();
113
+
114
+ setup.sac_contract.issuer().set_flag(IssuerFlags::RevocableFlag);
115
+ setup.sac_contract.issuer().set_flag(IssuerFlags::ClawbackEnabledFlag);
116
+
117
+ // Force redistribution path by blacklisting recipient.
118
+ mock_set_authorized_auth(&setup, &blacklisted_recipient, false);
119
+ setup.sac_manager_client.set_authorized(&blacklisted_recipient, &false);
120
+ assert!(!setup.sac_client.authorized(&blacklisted_recipient));
121
+
122
+ let config = SupplyControllerConfig {
123
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
124
+ allow_any_mint_burn: true,
125
+ whitelist_addresses: Vec::new(&setup.env),
126
+ };
127
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &controller, &Some(config.clone()));
128
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &controller, &Some(config));
129
+
130
+ let owner_balance_before = setup.sac_client.balance(&setup.owner);
131
+ let blacklisted_balance_before = setup.sac_client.balance(&blacklisted_recipient);
132
+
133
+ mock_authorized_mint_auth(&setup, &controller, &blacklisted_recipient, 700_i128);
134
+ setup.sac_manager_client.authorized_mint(&controller, &blacklisted_recipient, &700);
135
+
136
+ let expected = SupplyIncreased { controller: controller.clone(), to: blacklisted_recipient.clone(), amount: 700 };
137
+ let expected2 = RedistributeFunds { user: blacklisted_recipient.clone(), amount: 700 };
138
+ assert_contains_events(&setup.env, &setup.sac_manager, &[&expected, &expected2]);
139
+
140
+ assert_eq!(setup.sac_client.balance(&blacklisted_recipient), blacklisted_balance_before);
141
+ assert_eq!(setup.sac_client.balance(&setup.owner), owner_balance_before + 700);
142
+ }
143
+
144
+ #[test]
145
+ fn test_authorized_mint_succeeds_when_amount_equals_rate_limit() {
146
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
147
+ let recipient = setup.generate_address();
148
+ let controller = setup.generate_address();
149
+
150
+ let config = SupplyControllerConfig {
151
+ limit_config: LimitConfig { limit_capacity: 1_000, refill_per_second: 1 },
152
+ allow_any_mint_burn: true,
153
+ whitelist_addresses: Vec::new(&setup.env),
154
+ };
155
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &controller, &Some(config.clone()));
156
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &controller, &Some(config));
157
+
158
+ mock_authorized_mint_auth(&setup, &controller, &recipient, 1000_i128);
159
+ setup.sac_manager_client.authorized_mint(&controller, &recipient, &1000);
160
+ assert_eq!(setup.sac_client.balance(&recipient), 1000);
161
+ }
162
+
163
+ #[test]
164
+ fn test_authorized_mint_fails_when_amount_exceeds_rate_limit() {
165
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
166
+ let recipient = setup.generate_address();
167
+ let controller = setup.generate_address();
168
+
169
+ let config = SupplyControllerConfig {
170
+ limit_config: LimitConfig { limit_capacity: 1_000, refill_per_second: 1 },
171
+ allow_any_mint_burn: true,
172
+ whitelist_addresses: Vec::new(&setup.env),
173
+ };
174
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &controller, &Some(config.clone()));
175
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &controller, &Some(config));
176
+
177
+ mock_authorized_mint_auth(&setup, &controller, &recipient, 1001_i128);
178
+ let result = setup.sac_manager_client.try_authorized_mint(&controller, &recipient, &1001);
179
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::RateLimitExceeded.into());
180
+ }
181
+
182
+ #[test]
183
+ fn test_authorized_mint_fails_without_supply_controller_config() {
184
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
185
+ let recipient = setup.generate_address();
186
+ let random = setup.generate_address();
187
+
188
+ // Supply control enabled but sender is NOT a supply controller
189
+ mock_authorized_mint_auth(&setup, &random, &recipient, 1000_i128);
190
+ let result = setup.sac_manager_client.try_authorized_mint(&random, &recipient, &1000);
191
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::NotFound.into());
192
+ }
193
+
194
+ // =========================================================================
195
+ // authorized_mint Auth Tests
196
+ // =========================================================================
197
+
198
+ #[test]
199
+ #[should_panic(expected = "Error(Auth, InvalidAction)")]
200
+ fn test_authorized_mint_without_auth() {
201
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
202
+ let recipient = setup.generate_address();
203
+
204
+ // No auth mocked — sender.require_auth() fails
205
+ setup.sac_manager_client.authorized_mint(&setup.owner, &recipient, &1000);
206
+ }
@@ -0,0 +1,215 @@
1
+ //! Burn (MintBurnable) Integration Tests
2
+ //!
3
+ //! Burn tests use explicit mock_auth setup so nested auth for `sac.burn`
4
+ //! (`from.require_auth()`) is asserted deterministically.
5
+
6
+ use super::test_helper::{mock_sac_owner_mint_auth, mock_set_mint_whitelist_auth, mock_set_supply_controller_auth};
7
+ use crate::errors::SacManagerError;
8
+ use crate::extensions::supply_control::{LimitConfig, SupplyControlClient, SupplyControlError, SupplyControllerConfig};
9
+ use crate::tests::sac_manager::test_helper::mock_burn_auth;
10
+ use crate::tests::test_helper::{mock_auth, mock_oft_mint_auth, TestSetup};
11
+ use crate::extensions::supply_control::SupplyDecreased;
12
+ use soroban_sdk::Vec;
13
+ use utils::testing_utils::assert_contains_event;
14
+
15
+ // =========================================================================
16
+ // Burn Tests (with Supply Control)
17
+ // =========================================================================
18
+
19
+ #[test]
20
+ fn test_burn_by_oft_with_supply_control() {
21
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
22
+
23
+ let config = SupplyControllerConfig {
24
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
25
+ allow_any_mint_burn: true,
26
+ whitelist_addresses: Vec::new(&setup.env),
27
+ };
28
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &setup.oft, &Some(config.clone()));
29
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &setup.oft, &Some(config.clone()));
30
+
31
+ // Mint tokens to OFT
32
+ mock_oft_mint_auth(&setup, &setup.oft, 1000_i128);
33
+ setup.sac_manager_client.mint(&setup.oft, &1000);
34
+ assert_eq!(setup.sac_client.balance(&setup.oft), 1000);
35
+
36
+ // OFT burns its own tokens
37
+ mock_burn_auth(&setup, &setup.oft, 500_i128);
38
+ setup.sac_manager_client.burn(&setup.oft, &500);
39
+ let expected = SupplyDecreased { controller: setup.oft.clone(), from: setup.oft.clone(), amount: 500 };
40
+ assert_contains_event(&setup.env, &setup.sac_manager, expected);
41
+ assert_eq!(setup.sac_client.balance(&setup.oft), 500);
42
+ }
43
+
44
+ #[test]
45
+ fn test_burn_from_user_by_oft() {
46
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
47
+ let user = setup.generate_address();
48
+
49
+ let config = SupplyControllerConfig {
50
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
51
+ allow_any_mint_burn: true,
52
+ whitelist_addresses: Vec::new(&setup.env),
53
+ };
54
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &setup.oft, &Some(config.clone()));
55
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &setup.oft, &Some(config.clone()));
56
+
57
+ // Mint tokens to user
58
+ mock_oft_mint_auth(&setup, &user, 1000_i128);
59
+ setup.sac_manager_client.mint(&user, &1000);
60
+ assert_eq!(setup.sac_client.balance(&user), 1000);
61
+
62
+ // OFT burns tokens from user (user authorizes at SAC level)
63
+ mock_burn_auth(&setup, &user, 500_i128);
64
+ setup.sac_manager_client.burn(&user, &500);
65
+ let expected = SupplyDecreased { controller: setup.oft.clone(), from: user.clone(), amount: 500 };
66
+ assert_contains_event(&setup.env, &setup.sac_manager, expected);
67
+ assert_eq!(setup.sac_client.balance(&user), 500);
68
+ }
69
+
70
+ #[test]
71
+ fn test_burn_from_self_fails_when_allow_any_mint_burn_is_false() {
72
+ let setup = TestSetup::new().with_supply_control_enabled().build();
73
+
74
+ let config = SupplyControllerConfig {
75
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
76
+ allow_any_mint_burn: false,
77
+ whitelist_addresses: Vec::new(&setup.env),
78
+ };
79
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &setup.oft, &Some(config.clone()));
80
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &setup.oft, &Some(config.clone()));
81
+
82
+ // Mint to OFT directly via SAC owner
83
+ mock_sac_owner_mint_auth(&setup, &setup.oft, 1000_i128);
84
+ setup.sac_client.mint(&setup.oft, &1000);
85
+ assert_eq!(setup.sac_client.balance(&setup.oft), 1000);
86
+
87
+ // Burn-from-self should fail when allow_any_mint_burn is false
88
+ mock_burn_auth(&setup, &setup.oft, 500_i128);
89
+ let result = setup.sac_manager_client.try_burn(&setup.oft, &500);
90
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::CannotBurnFromAddress.into());
91
+ }
92
+
93
+ // =========================================================================
94
+ // Burn Error Cases (Supply Control)
95
+ // =========================================================================
96
+
97
+ #[test]
98
+ fn test_burn_fails_when_oft_not_supply_controller() {
99
+ let setup = TestSetup::new().with_supply_control_enabled().build();
100
+ let user = setup.generate_address();
101
+
102
+ // Mint tokens to user directly via SAC (bypassing supply control).
103
+ // Here SAC admin is still owner (not sac_manager), so owner can mint.
104
+ mock_sac_owner_mint_auth(&setup, &user, 1000_i128);
105
+ setup.sac_client.mint(&user, &1000);
106
+
107
+ // OFT is NOT added as supply controller — burn should fail
108
+ mock_burn_auth(&setup, &user, 500_i128);
109
+ let result = setup.sac_manager_client.try_burn(&user, &500);
110
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::NotFound.into());
111
+ }
112
+
113
+ #[test]
114
+ fn test_burn_fails_when_controller_cannot_burn_from_address() {
115
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
116
+ let user = setup.generate_address();
117
+
118
+ // OFT as controller WITHOUT allow_any_mint_burn
119
+ let config = SupplyControllerConfig {
120
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
121
+ allow_any_mint_burn: false,
122
+ whitelist_addresses: Vec::new(&setup.env),
123
+ };
124
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &setup.oft, &Some(config.clone()));
125
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &setup.oft, &Some(config.clone()));
126
+
127
+ // Whitelist user for OFT controller to allow minting (allow_any=false)
128
+ let sc_client = SupplyControlClient::new(&setup.env, &setup.sac_manager);
129
+ mock_set_mint_whitelist_auth(&setup, &setup.sc_manager, &setup.oft, &user, true);
130
+ sc_client.set_mint_whitelist(&setup.sc_manager, &setup.oft, &user, &true);
131
+
132
+ // Mint tokens to user
133
+ mock_oft_mint_auth(&setup, &user, 1000_i128);
134
+ setup.sac_manager_client.mint(&user, &1000);
135
+
136
+ // OFT tries to burn from user without allow_any_mint_burn - should fail
137
+ mock_burn_auth(&setup, &user, 500_i128);
138
+ let result = setup.sac_manager_client.try_burn(&user, &500);
139
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::CannotBurnFromAddress.into());
140
+ }
141
+
142
+ // =========================================================================
143
+ // Burn Tests (without Supply Control) — OFT calls burn
144
+ // =========================================================================
145
+
146
+ #[test]
147
+ fn test_burn_by_oft_without_supply_control() {
148
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
149
+
150
+ // Supply control is disabled by default
151
+ assert!(!setup.sac_manager_client.supply_control_enabled());
152
+
153
+ // Mint tokens to OFT first
154
+ mock_oft_mint_auth(&setup, &setup.oft, 1000_i128);
155
+ setup.sac_manager_client.mint(&setup.oft, &1000);
156
+ assert_eq!(setup.sac_client.balance(&setup.oft), 1000);
157
+
158
+ // OFT can burn when supply control is disabled
159
+ mock_burn_auth(&setup, &setup.oft, 500_i128);
160
+ setup.sac_manager_client.burn(&setup.oft, &500);
161
+ assert_eq!(setup.sac_client.balance(&setup.oft), 500);
162
+ }
163
+
164
+ #[test]
165
+ fn test_burn_fails_when_amount_exceeds_balance() {
166
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
167
+
168
+ mock_oft_mint_auth(&setup, &setup.oft, 100_i128);
169
+ setup.sac_manager_client.mint(&setup.oft, &100);
170
+ assert_eq!(setup.sac_client.balance(&setup.oft), 100);
171
+
172
+ mock_burn_auth(&setup, &setup.oft, 200_i128);
173
+ let result = setup.sac_manager_client.try_burn(&setup.oft, &200);
174
+ assert!(result.is_err());
175
+ }
176
+
177
+ #[test]
178
+ fn test_burn_fails_when_oft_not_set() {
179
+ let setup = TestSetup::new().without_oft().build();
180
+ let user = setup.generate_address();
181
+
182
+ // Mock from auth so we pass from.require_auth() and reach the OFT address check
183
+ mock_auth(&setup.env, &setup.sac_manager, &user, "burn", (&user, 500_i128));
184
+ let result = setup.sac_manager_client.try_burn(&user, &500);
185
+ assert_eq!(result.err().unwrap().unwrap(), SacManagerError::OftAddressNotSet.into());
186
+ }
187
+
188
+ // =========================================================================
189
+ // Burn Auth Tests
190
+ // =========================================================================
191
+
192
+ #[test]
193
+ #[should_panic(expected = "Error(Auth, InvalidAction)")]
194
+ fn test_burn_fails_without_oft_auth() {
195
+ // No mock_burn_auth — the OFT address won't be authorized
196
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
197
+ let user = setup.generate_address();
198
+
199
+ setup.sac_manager_client.burn(&user, &500);
200
+ }
201
+
202
+ #[test]
203
+ #[should_panic(expected = "Error(Auth, InvalidAction)")]
204
+ fn test_burn_fails_without_from_auth_even_if_oft_auth_present() {
205
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
206
+ let user = setup.generate_address();
207
+
208
+ mock_oft_mint_auth(&setup, &user, 1000_i128);
209
+ setup.sac_manager_client.mint(&user, &1000);
210
+ assert_eq!(setup.sac_client.balance(&user), 1000);
211
+
212
+ // Only root OFT auth is mocked; nested SAC burn auth for `from` is intentionally missing.
213
+ mock_auth(&setup.env, &setup.sac_manager, &setup.oft, "burn", (&user, 500_i128));
214
+ setup.sac_manager_client.burn(&user, &500);
215
+ }
@@ -0,0 +1,209 @@
1
+ //! Clawback Integration Tests
2
+ //!
3
+ //! Tests for admin-initiated clawback functionality via `clawback`.
4
+ //! The clawback operation uses SAC clawback, which requires AUTH_CLAWBACK_ENABLED
5
+ //! flag on the SAC issuer.
6
+ //!
7
+ //! Core burn logic (supply control validation) is shared with MintBurnable::burn
8
+ //! in `burn.rs`. These tests focus on clawback-specific behavior: auth, owner
9
+ //! fallback, clawback mechanics, and supply controllers calling directly.
10
+
11
+ use super::test_helper::{mock_authorized_mint_auth, mock_clawback_auth, mock_set_supply_controller_auth};
12
+ use crate::errors::SacManagerError;
13
+ use crate::extensions::supply_control::{LimitConfig, SupplyControlError, SupplyControllerConfig, SupplyDecreased};
14
+ use crate::tests::test_helper::TestSetup;
15
+ use soroban_sdk::{testutils::IssuerFlags, Vec};
16
+ use utils::testing_utils::assert_contains_event;
17
+
18
+ // =========================================================================
19
+ // clawback Tests (without Supply Control — owner only)
20
+ // =========================================================================
21
+
22
+ #[test]
23
+ fn test_clawback_by_owner() {
24
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
25
+ let user = setup.generate_address();
26
+
27
+ setup.sac_contract.issuer().set_flag(IssuerFlags::RevocableFlag);
28
+ setup.sac_contract.issuer().set_flag(IssuerFlags::ClawbackEnabledFlag);
29
+
30
+ // Mint tokens to user first
31
+ mock_authorized_mint_auth(&setup, &setup.owner, &user, 1000_i128);
32
+ setup.sac_manager_client.authorized_mint(&setup.owner, &user, &1000);
33
+ assert_eq!(setup.sac_client.balance(&user), 1000);
34
+
35
+ // Owner clawbacks tokens from user (no SupplyDecreased event when supply control is off)
36
+ mock_clawback_auth(&setup, &setup.owner, &user, 500_i128);
37
+ setup.sac_manager_client.clawback(&setup.owner, &user, &500);
38
+ assert_eq!(setup.sac_client.balance(&user), 500);
39
+ }
40
+
41
+ #[test]
42
+ fn test_clawback_full_balance() {
43
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
44
+ let user = setup.generate_address();
45
+
46
+ setup.sac_contract.issuer().set_flag(IssuerFlags::RevocableFlag);
47
+ setup.sac_contract.issuer().set_flag(IssuerFlags::ClawbackEnabledFlag);
48
+
49
+ mock_authorized_mint_auth(&setup, &setup.owner, &user, 1000_i128);
50
+ setup.sac_manager_client.authorized_mint(&setup.owner, &user, &1000);
51
+
52
+ // Clawback full balance (boundary case: amount == balance)
53
+ mock_clawback_auth(&setup, &setup.owner, &user, 1000_i128);
54
+ setup.sac_manager_client.clawback(&setup.owner, &user, &1000);
55
+ assert_eq!(setup.sac_client.balance(&user), 0);
56
+ }
57
+
58
+ #[test]
59
+ fn test_clawback_fails_when_amount_exceeds_balance() {
60
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
61
+ let user = setup.generate_address();
62
+
63
+ setup.sac_contract.issuer().set_flag(IssuerFlags::RevocableFlag);
64
+ setup.sac_contract.issuer().set_flag(IssuerFlags::ClawbackEnabledFlag);
65
+
66
+ mock_authorized_mint_auth(&setup, &setup.owner, &user, 100_i128);
67
+ setup.sac_manager_client.authorized_mint(&setup.owner, &user, &100);
68
+
69
+ mock_clawback_auth(&setup, &setup.owner, &user, 200_i128);
70
+ let result = setup.sac_manager_client.try_clawback(&setup.owner, &user, &200);
71
+ assert!(result.is_err());
72
+ }
73
+
74
+ #[test]
75
+ fn test_clawback_by_non_owner_fails_without_supply_control() {
76
+ let setup = TestSetup::new().with_manager_as_sac_admin().build();
77
+ let user = setup.generate_address();
78
+ let random = setup.generate_address();
79
+
80
+ // Supply control is off — only owner can call
81
+ mock_clawback_auth(&setup, &random, &user, 500_i128);
82
+ let result = setup.sac_manager_client.try_clawback(&random, &user, &500);
83
+ assert_eq!(result.err().unwrap().unwrap(), SacManagerError::Unauthorized.into());
84
+ }
85
+
86
+ // =========================================================================
87
+ // clawback Tests (with Supply Control)
88
+ // =========================================================================
89
+
90
+ #[test]
91
+ fn test_clawback_by_supply_controller() {
92
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
93
+ let user = setup.generate_address();
94
+ let controller = setup.generate_address();
95
+
96
+ setup.sac_contract.issuer().set_flag(IssuerFlags::RevocableFlag);
97
+ setup.sac_contract.issuer().set_flag(IssuerFlags::ClawbackEnabledFlag);
98
+
99
+ let config = SupplyControllerConfig {
100
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
101
+ allow_any_mint_burn: true,
102
+ whitelist_addresses: Vec::new(&setup.env),
103
+ };
104
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &controller, &Some(config.clone()));
105
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &controller, &Some(config));
106
+
107
+ // Mint tokens to user via controller
108
+ mock_authorized_mint_auth(&setup, &controller, &user, 1000_i128);
109
+ setup.sac_manager_client.authorized_mint(&controller, &user, &1000);
110
+ assert_eq!(setup.sac_client.balance(&user), 1000);
111
+
112
+ // Controller clawbacks from user
113
+ mock_clawback_auth(&setup, &controller, &user, 500_i128);
114
+ setup.sac_manager_client.clawback(&controller, &user, &500);
115
+
116
+ let expected = SupplyDecreased { controller: controller.clone(), from: user.clone(), amount: 500 };
117
+ assert_contains_event(&setup.env, &setup.sac_manager, expected);
118
+
119
+ assert_eq!(setup.sac_client.balance(&user), 500);
120
+ }
121
+
122
+ #[test]
123
+ fn test_clawback_by_owner_fails_with_supply_control_without_config() {
124
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
125
+ let user = setup.generate_address();
126
+
127
+ setup.sac_contract.issuer().set_flag(IssuerFlags::RevocableFlag);
128
+ setup.sac_contract.issuer().set_flag(IssuerFlags::ClawbackEnabledFlag);
129
+
130
+ // Owner is not auto-authorized when supply control is enabled and has no controller config.
131
+ mock_clawback_auth(&setup, &setup.owner, &user, 500_i128);
132
+ let result = setup.sac_manager_client.try_clawback(&setup.owner, &user, &500);
133
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::NotFound.into());
134
+ }
135
+
136
+ #[test]
137
+ fn test_clawback_fails_without_supply_controller_config() {
138
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
139
+ let user = setup.generate_address();
140
+ let random = setup.generate_address();
141
+
142
+ // Supply control enabled but sender is NOT a supply controller
143
+ mock_clawback_auth(&setup, &random, &user, 500_i128);
144
+ let result = setup.sac_manager_client.try_clawback(&random, &user, &500);
145
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::NotFound.into());
146
+ }
147
+
148
+ #[test]
149
+ fn test_clawback_fails_when_controller_cannot_burn_from_address() {
150
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
151
+ let user = setup.generate_address();
152
+ let controller = setup.generate_address();
153
+
154
+ // Controller WITHOUT allow_any_mint_burn
155
+ let config = SupplyControllerConfig {
156
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
157
+ allow_any_mint_burn: false,
158
+ whitelist_addresses: Vec::new(&setup.env),
159
+ };
160
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &controller, &Some(config.clone()));
161
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &controller, &Some(config));
162
+
163
+ // Controller tries to burn from user without allow_any_mint_burn — should fail
164
+ mock_clawback_auth(&setup, &controller, &user, 500_i128);
165
+ let result = setup.sac_manager_client.try_clawback(&controller, &user, &500);
166
+ assert_eq!(result.err().unwrap().unwrap(), SupplyControlError::CannotBurnFromAddress.into());
167
+ }
168
+
169
+ #[test]
170
+ fn test_clawback_by_controller_from_self() {
171
+ let setup = TestSetup::new().with_manager_as_sac_admin().with_supply_control_enabled().build();
172
+ let controller = setup.generate_address();
173
+
174
+ setup.sac_contract.issuer().set_flag(IssuerFlags::RevocableFlag);
175
+ setup.sac_contract.issuer().set_flag(IssuerFlags::ClawbackEnabledFlag);
176
+
177
+ // Controller WITH allow_any_mint_burn — required for any burn including from self
178
+ let config = SupplyControllerConfig {
179
+ limit_config: LimitConfig { limit_capacity: 10_000, refill_per_second: 0 },
180
+ allow_any_mint_burn: true,
181
+ whitelist_addresses: Vec::new(&setup.env),
182
+ };
183
+ mock_set_supply_controller_auth(&setup, &setup.sc_manager, &controller, &Some(config.clone()));
184
+ setup.sac_manager_client.set_supply_controller(&setup.sc_manager, &controller, &Some(config));
185
+
186
+ // Mint tokens to controller itself
187
+ mock_authorized_mint_auth(&setup, &controller, &controller, 1000_i128);
188
+ setup.sac_manager_client.authorized_mint(&controller, &controller, &1000);
189
+ assert_eq!(setup.sac_client.balance(&controller), 1000);
190
+
191
+ // Controller clawbacks from self — requires allow_any_mint_burn
192
+ mock_clawback_auth(&setup, &controller, &controller, 500_i128);
193
+ setup.sac_manager_client.clawback(&controller, &controller, &500);
194
+ assert_eq!(setup.sac_client.balance(&controller), 500);
195
+ }
196
+
197
+ // =========================================================================
198
+ // clawback Auth Tests
199
+ // =========================================================================
200
+
201
+ #[test]
202
+ #[should_panic(expected = "Error(Auth, InvalidAction)")]
203
+ fn test_clawback_fails_without_auth() {
204
+ let setup = TestSetup::new().build();
205
+ let user = setup.generate_address();
206
+
207
+ // Should panic because sender doesn't authorize the call
208
+ setup.sac_manager_client.clawback(&setup.owner, &user, &300);
209
+ }