@layerzerolabs/protocol-stellar-v2 0.2.33 → 0.2.35

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 (123) hide show
  1. package/.turbo/turbo-build.log +351 -367
  2. package/.turbo/turbo-lint.log +220 -223
  3. package/.turbo/turbo-test.log +1993 -1796
  4. package/Cargo.lock +10 -10
  5. package/Cargo.toml +1 -1
  6. package/contracts/common-macros/src/storage.rs +7 -5
  7. package/contracts/common-macros/src/tests/storage/snapshots/common_macros__tests__storage__generate_storage__snapshot_generated_storage_code.snap +3 -3
  8. package/contracts/endpoint-v2/src/endpoint_v2.rs +5 -4
  9. package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +7 -8
  10. package/contracts/endpoint-v2/src/messaging_channel.rs +78 -45
  11. package/contracts/endpoint-v2/src/storage.rs +8 -3
  12. package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +2 -2
  13. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +12 -15
  14. package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +46 -9
  15. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +7 -23
  16. package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +23 -20
  17. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +94 -1
  18. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_nonce.rs +17 -15
  19. package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -1
  20. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +48 -13
  21. package/contracts/endpoint-v2/src/tests/messaging_channel/pending_inbound_nonces.rs +111 -0
  22. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +15 -25
  23. package/contracts/layerzero-views/src/layerzero_view.rs +2 -2
  24. package/contracts/layerzero-views/src/tests/layerzero_view_tests.rs +3 -4
  25. package/contracts/layerzero-views/src/tests/setup.rs +0 -21
  26. package/contracts/message-libs/blocked-message-lib/src/lib.rs +4 -4
  27. package/contracts/message-libs/uln-302/src/send_uln.rs +5 -5
  28. package/contracts/oapps/counter/src/counter.rs +6 -0
  29. package/contracts/oapps/oapp/src/oapp_sender.rs +3 -2
  30. package/contracts/oapps/oft/integration-tests/extensions/test_oft_fee.rs +5 -11
  31. package/contracts/oapps/oft/integration-tests/extensions/test_pausable.rs +7 -14
  32. package/contracts/oapps/oft/integration-tests/extensions/test_rate_limiter.rs +11 -22
  33. package/contracts/oapps/oft/integration-tests/setup.rs +59 -7
  34. package/contracts/oapps/oft/integration-tests/utils.rs +28 -2
  35. package/contracts/oapps/oft/src/extensions/oft_fee.rs +5 -0
  36. package/contracts/oapps/oft/src/interfaces/mintable.rs +14 -0
  37. package/contracts/oapps/oft/src/interfaces/mod.rs +2 -2
  38. package/contracts/oapps/oft/src/oft.rs +8 -7
  39. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +8 -8
  40. package/contracts/oapps/oft/src/oft_types/mod.rs +3 -4
  41. package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +7 -5
  42. package/contracts/oapps/sac-manager/src/errors.rs +14 -0
  43. package/contracts/{sac-manager → oapps/sac-manager}/src/lib.rs +0 -4
  44. package/contracts/oapps/sac-manager/src/sac_manager.rs +115 -0
  45. package/contracts/oapps/sac-manager/src/storage.rs +20 -0
  46. package/contracts/{sac-manager → oapps/sac-manager}/src/tests/mod.rs +0 -4
  47. package/contracts/oapps/sac-manager/src/tests/sac_manager/clawback.rs +86 -0
  48. package/contracts/oapps/sac-manager/src/tests/sac_manager/mint.rs +58 -0
  49. package/contracts/{sac-manager → oapps/sac-manager}/src/tests/sac_manager/mod.rs +1 -3
  50. package/contracts/oapps/sac-manager/src/tests/sac_manager/set_minter.rs +69 -0
  51. package/contracts/oapps/sac-manager/src/tests/sac_manager/test_helper.rs +18 -0
  52. package/contracts/oapps/sac-manager/src/tests/sac_manager/view_functions.rs +28 -0
  53. package/contracts/{sac-manager → oapps/sac-manager}/src/tests/test_helper.rs +16 -59
  54. package/docs/layerzero-v2-on-stellar.md +46 -2
  55. package/package.json +8 -3
  56. package/sdk/.turbo/turbo-test.log +424 -429
  57. package/sdk/dist/generated/bml.d.ts +3 -3
  58. package/sdk/dist/generated/bml.js +3 -3
  59. package/sdk/dist/generated/counter.d.ts +32 -3
  60. package/sdk/dist/generated/counter.js +6 -3
  61. package/sdk/dist/generated/dvn.d.ts +3 -3
  62. package/sdk/dist/generated/dvn.js +3 -3
  63. package/sdk/dist/generated/dvn_fee_lib.d.ts +2 -2
  64. package/sdk/dist/generated/dvn_fee_lib.js +2 -2
  65. package/sdk/dist/generated/endpoint.d.ts +12 -13
  66. package/sdk/dist/generated/endpoint.js +7 -7
  67. package/sdk/dist/generated/executor.d.ts +3 -3
  68. package/sdk/dist/generated/executor.js +3 -3
  69. package/sdk/dist/generated/executor_fee_lib.d.ts +2 -2
  70. package/sdk/dist/generated/executor_fee_lib.js +2 -2
  71. package/sdk/dist/generated/executor_helper.d.ts +2 -2
  72. package/sdk/dist/generated/executor_helper.js +2 -2
  73. package/sdk/dist/generated/layerzero_view.d.ts +3 -3
  74. package/sdk/dist/generated/layerzero_view.js +3 -3
  75. package/sdk/dist/generated/oft.d.ts +32 -3
  76. package/sdk/dist/generated/oft.js +7 -4
  77. package/sdk/dist/generated/price_feed.d.ts +3 -3
  78. package/sdk/dist/generated/price_feed.js +3 -3
  79. package/sdk/dist/generated/sac_manager.d.ts +47 -318
  80. package/sdk/dist/generated/sac_manager.js +24 -129
  81. package/sdk/dist/generated/sml.d.ts +2 -2
  82. package/sdk/dist/generated/sml.js +2 -2
  83. package/sdk/dist/generated/treasury.d.ts +2 -2
  84. package/sdk/dist/generated/treasury.js +2 -2
  85. package/sdk/dist/generated/uln302.d.ts +3 -3
  86. package/sdk/dist/generated/uln302.js +3 -3
  87. package/sdk/dist/generated/upgrader.d.ts +2 -2
  88. package/sdk/dist/generated/upgrader.js +2 -2
  89. package/sdk/package.json +6 -1
  90. package/sdk/test/oft-sml.test.ts +72 -36
  91. package/sdk/test/sac-manager-redistribution.test.ts +38 -182
  92. package/contracts/endpoint-v2/src/tests/messaging_channel/lazy_inbound_nonce.rs +0 -39
  93. package/contracts/oapps/oft/src/interfaces/mint_burnable.rs +0 -18
  94. package/contracts/sac-manager/src/errors.rs +0 -18
  95. package/contracts/sac-manager/src/extensions/mod.rs +0 -6
  96. package/contracts/sac-manager/src/extensions/redistribution.rs +0 -109
  97. package/contracts/sac-manager/src/extensions/supply_control/mod.rs +0 -488
  98. package/contracts/sac-manager/src/extensions/supply_control/rate_limit.rs +0 -126
  99. package/contracts/sac-manager/src/interfaces/mod.rs +0 -3
  100. package/contracts/sac-manager/src/interfaces/sac_manager.rs +0 -52
  101. package/contracts/sac-manager/src/sac_manager.rs +0 -193
  102. package/contracts/sac-manager/src/storage.rs +0 -20
  103. package/contracts/sac-manager/src/tests/redistribution/mod.rs +0 -1
  104. package/contracts/sac-manager/src/tests/redistribution/redistribute_funds.rs +0 -82
  105. package/contracts/sac-manager/src/tests/sac_manager/admin_mint.rs +0 -206
  106. package/contracts/sac-manager/src/tests/sac_manager/burn.rs +0 -215
  107. package/contracts/sac-manager/src/tests/sac_manager/clawback.rs +0 -209
  108. package/contracts/sac-manager/src/tests/sac_manager/mint.rs +0 -252
  109. package/contracts/sac-manager/src/tests/sac_manager/set_oft_address.rs +0 -47
  110. package/contracts/sac-manager/src/tests/sac_manager/test_helper.rs +0 -75
  111. package/contracts/sac-manager/src/tests/sac_manager/view_functions.rs +0 -60
  112. package/contracts/sac-manager/src/tests/supply_control/enumerable_set.rs +0 -256
  113. package/contracts/sac-manager/src/tests/supply_control/mod.rs +0 -8
  114. package/contracts/sac-manager/src/tests/supply_control/refill.rs +0 -90
  115. package/contracts/sac-manager/src/tests/supply_control/set_mint_whitelist.rs +0 -245
  116. package/contracts/sac-manager/src/tests/supply_control/set_supply_controller.rs +0 -267
  117. package/contracts/sac-manager/src/tests/supply_control/set_supply_controller_manager.rs +0 -122
  118. package/contracts/sac-manager/src/tests/supply_control/test_helper.rs +0 -38
  119. package/contracts/sac-manager/src/tests/supply_control/update_allow_any_mint_burn.rs +0 -114
  120. package/contracts/sac-manager/src/tests/supply_control/update_limit_config.rs +0 -257
  121. /package/contracts/{sac-manager → oapps/sac-manager}/Cargo.toml +0 -0
  122. /package/contracts/{sac-manager → oapps/sac-manager}/src/tests/sac_manager/set_admin.rs +0 -0
  123. /package/contracts/{sac-manager → oapps/sac-manager}/src/tests/sac_manager/set_authorized.rs +0 -0
@@ -53,7 +53,7 @@ fn test_skip_requires_auth_even_when_caller_is_receiver() {
53
53
  endpoint_client.skip(&receiver, &receiver, &src_eid, &sender, &nonce);
54
54
  }
55
55
 
56
- // Successful skip updates inbound/lazy nonces and emits InboundNonceSkipped
56
+ // Successful skip updates inbound nonce and emits InboundNonceSkipped
57
57
  #[test]
58
58
  fn test_skip_success() {
59
59
  let context = setup();
@@ -65,13 +65,10 @@ fn test_skip_success() {
65
65
  let sender = BytesN::from_array(env, &[1u8; 32]);
66
66
  let nonce = 1;
67
67
 
68
- // Verify initial state: lazy inbound nonce should be 0.
69
- let initial_lazy_nonce = endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender);
70
- assert_eq!(initial_lazy_nonce, 0, "Initial lazy inbound nonce should be 0");
71
-
72
68
  // Initially, inbound nonce should be 0.
73
69
  let initial_nonce = endpoint_client.inbound_nonce(&receiver, &src_eid, &sender);
74
70
  assert_eq!(initial_nonce, 0);
71
+ assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
75
72
 
76
73
  // Skip nonce 1 (expected nonce is initial_nonce + 1 = 1).
77
74
  skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, nonce);
@@ -86,10 +83,7 @@ fn test_skip_success() {
86
83
  // Verify inbound nonce reflects the skip via public interface.
87
84
  let updated_nonce = endpoint_client.inbound_nonce(&receiver, &src_eid, &sender);
88
85
  assert_eq!(updated_nonce, nonce);
89
-
90
- // Verify lazy inbound nonce was updated.
91
- let lazy_nonce = endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender);
92
- assert_eq!(lazy_nonce, nonce);
86
+ assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
93
87
  }
94
88
 
95
89
  // Multiple sequential skips update to the latest nonce
@@ -111,13 +105,10 @@ fn test_skip_multiple_nonces() {
111
105
  let nonce2 = 2;
112
106
  skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, nonce2);
113
107
 
114
- // Verify lazy inbound nonce was updated to nonce2.
115
- let lazy_nonce = endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender);
116
- assert_eq!(lazy_nonce, nonce2);
117
-
118
108
  // Verify inbound nonce reflects the latest skip.
119
109
  let updated_nonce = endpoint_client.inbound_nonce(&receiver, &src_eid, &sender);
120
110
  assert_eq!(updated_nonce, nonce2);
111
+ assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
121
112
  }
122
113
 
123
114
  // Delegate authorization (delegate(receiver) is allowed)
@@ -146,9 +137,8 @@ fn test_skip_with_delegate() {
146
137
  InboundNonceSkipped { src_eid, sender: sender.clone(), receiver: receiver.clone(), nonce },
147
138
  );
148
139
 
149
- // Verify lazy inbound nonce was updated.
150
- let lazy_nonce = endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender);
151
- assert_eq!(lazy_nonce, nonce);
140
+ assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), nonce);
141
+ assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
152
142
  }
153
143
 
154
144
  // Path isolation (receiver/src_eid/sender are isolated)
@@ -176,11 +166,11 @@ fn test_skip_different_paths() {
176
166
  // Skip for different senders.
177
167
  skip_with_auth(&context, &receiver1, &receiver1, src_eid1, &sender2, nonce);
178
168
 
179
- // Verify all paths have independent lazy nonces.
180
- assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver1, &src_eid1, &sender1), nonce);
181
- assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver2, &src_eid1, &sender1), nonce);
182
- assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver1, &src_eid2, &sender1), nonce);
183
- assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver1, &src_eid1, &sender2), nonce);
169
+ // Verify all paths have independent inbound nonces.
170
+ assert_eq!(endpoint_client.inbound_nonce(&receiver1, &src_eid1, &sender1), nonce);
171
+ assert_eq!(endpoint_client.inbound_nonce(&receiver2, &src_eid1, &sender1), nonce);
172
+ assert_eq!(endpoint_client.inbound_nonce(&receiver1, &src_eid2, &sender1), nonce);
173
+ assert_eq!(endpoint_client.inbound_nonce(&receiver1, &src_eid1, &sender2), nonce);
184
174
  }
185
175
 
186
176
  // Invalid nonce rejection (must match expected nonce)
@@ -224,10 +214,10 @@ fn test_skip_next_nonce_accounts_for_verified_payload_hashes() {
224
214
  let result = endpoint_client.try_skip(&receiver, &receiver, &src_eid, &sender, &1);
225
215
  assert_eq!(result.err().unwrap().ok().unwrap(), EndpointError::InvalidNonce.into());
226
216
 
227
- // Skipping 2 should succeed and advance lazy inbound nonce to 2.
217
+ // Skipping 2 should succeed and advance inbound nonce to 2.
228
218
  skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, 2);
229
- assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 2);
230
219
  assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
220
+ assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
231
221
 
232
222
  // skip() does not clear any existing payload hashes.
233
223
  assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &1), Some(payload_hash_1));
@@ -251,8 +241,8 @@ fn test_skip_closes_gap_and_advances_inbound_nonce() {
251
241
 
252
242
  // Skip nonce 1 to close the gap. This should allow inbound_nonce to advance to 2.
253
243
  skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, 1);
254
- assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 1);
255
244
  assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
245
+ assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
256
246
 
257
247
  // Payload hash at nonce 2 remains intact.
258
248
  assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &2), Some(payload_hash_2));
@@ -271,7 +261,7 @@ fn test_skip_rejects_repeated_same_nonce() {
271
261
 
272
262
  // Skip nonce 1 successfully.
273
263
  skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, 1);
274
- assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 1);
264
+ assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 1);
275
265
 
276
266
  // Skipping nonce 1 again should fail since the next expected nonce is now 2.
277
267
  context.mock_auth(&receiver, "skip", (&receiver, &receiver, &src_eid, &sender, &1u64));
@@ -104,9 +104,9 @@ impl LayerZeroView {
104
104
  let empty_hash = empty_payload_hash(env);
105
105
  let nil_hash = nil_payload_hash(env);
106
106
 
107
- // Executed: payload hash has been cleared (None) and nonce <= lazy_inbound_nonce
107
+ // Executed: payload hash has been cleared (None) and nonce <= inbound_nonce
108
108
  if payload_hash.is_none()
109
- && origin.nonce <= messaging_channel.lazy_inbound_nonce(receiver, &origin.src_eid, &origin.sender)
109
+ && origin.nonce <= messaging_channel.inbound_nonce(receiver, &origin.src_eid, &origin.sender)
110
110
  {
111
111
  return ExecutionState::Executed;
112
112
  }
@@ -206,9 +206,9 @@ fn test_executable_state_executed() {
206
206
  let receiver = test_setup.register_oapp();
207
207
  let sender = soroban_sdk::Address::generate(&test_setup.env);
208
208
 
209
- // Clear payload hash (None) and set lazy_inbound_nonce >= nonce = Executed
209
+ // Clear payload hash (None) and set inbound_nonce >= nonce = Executed
210
210
  test_setup.set_payload_hash(&receiver, REMOTE_EID, &sender, 1, &None);
211
- test_setup.set_lazy_inbound_nonce(&receiver, REMOTE_EID, &sender, 1);
211
+ test_setup.set_inbound_nonce(&receiver, REMOTE_EID, &sender, 1);
212
212
 
213
213
  let origin = Origin { src_eid: REMOTE_EID, sender: address_to_bytes32(&sender), nonce: 1 };
214
214
 
@@ -262,9 +262,8 @@ fn test_executable_multiple_nonces_in_sequence() {
262
262
  assert_eq!(test_setup.view_client.executable(&origin_2, &receiver), ExecutionState::VerifiedButNotExecutable);
263
263
  assert_eq!(test_setup.view_client.executable(&origin_3, &receiver), ExecutionState::VerifiedButNotExecutable);
264
264
 
265
- // Now execute nonce 1 (set lazy_inbound_nonce)
265
+ // Now execute nonce 1 (clear payload hash, advance inbound_nonce)
266
266
  test_setup.set_payload_hash(&receiver, REMOTE_EID, &sender, 1, &None);
267
- test_setup.set_lazy_inbound_nonce(&receiver, REMOTE_EID, &sender, 1);
268
267
  test_setup.set_inbound_nonce(&receiver, REMOTE_EID, &sender, 2);
269
268
 
270
269
  assert_eq!(test_setup.view_client.executable(&origin_1, &receiver), ExecutionState::Executed);
@@ -30,7 +30,6 @@ mod endpoint_storage {
30
30
  Initializable(Address, u32, BytesN<32>),
31
31
  Verifiable(Address, u32, BytesN<32>),
32
32
  // State for executable tests
33
- LazyInboundNonce(Address, u32, BytesN<32>),
34
33
  InboundNonce(Address, u32, BytesN<32>),
35
34
  InboundPayloadHash(Address, u32, BytesN<32>, u64),
36
35
  ReceiveLibrary(Address, u32),
@@ -91,13 +90,6 @@ impl MockEndpoint {
91
90
  .set(&endpoint_storage::MockEndpointStorage::Verifiable(receiver.clone(), *src_eid, sender.clone()), value);
92
91
  }
93
92
 
94
- pub fn set_lazy_inbound_nonce(env: &Env, receiver: &Address, src_eid: &u32, sender: &BytesN<32>, nonce: &u64) {
95
- env.storage().persistent().set(
96
- &endpoint_storage::MockEndpointStorage::LazyInboundNonce(receiver.clone(), *src_eid, sender.clone()),
97
- nonce,
98
- );
99
- }
100
-
101
93
  pub fn set_inbound_nonce(env: &Env, receiver: &Address, src_eid: &u32, sender: &BytesN<32>, nonce: &u64) {
102
94
  env.storage().persistent().set(
103
95
  &endpoint_storage::MockEndpointStorage::InboundNonce(receiver.clone(), *src_eid, sender.clone()),
@@ -135,13 +127,6 @@ impl MockEndpoint {
135
127
  // Getters required by LayerZeroView
136
128
  // =========================================================================
137
129
 
138
- pub fn lazy_inbound_nonce(env: &Env, receiver: &Address, src_eid: &u32, sender: &BytesN<32>) -> u64 {
139
- env.storage()
140
- .persistent()
141
- .get(&endpoint_storage::MockEndpointStorage::LazyInboundNonce(receiver.clone(), *src_eid, sender.clone()))
142
- .unwrap_or(0)
143
- }
144
-
145
130
  pub fn inbound_nonce(env: &Env, receiver: &Address, src_eid: &u32, sender: &BytesN<32>) -> u64 {
146
131
  env.storage()
147
132
  .persistent()
@@ -282,12 +267,6 @@ impl<'a> TestSetup<'a> {
282
267
  self.endpoint_client.set_verifiable(receiver, &src_eid, &sender_bytes32, &value);
283
268
  }
284
269
 
285
- /// Set lazy inbound nonce (marks messages up to this nonce as processed).
286
- pub fn set_lazy_inbound_nonce(&self, receiver: &Address, src_eid: u32, sender: &Address, nonce: u64) {
287
- let sender_bytes32 = address_to_bytes32(sender);
288
- self.endpoint_client.set_lazy_inbound_nonce(receiver, &src_eid, &sender_bytes32, &nonce);
289
- }
290
-
291
270
  /// Set inbound nonce (marks messages up to this nonce as verified and executable).
292
271
  pub fn set_inbound_nonce(&self, receiver: &Address, src_eid: u32, sender: &Address, nonce: u64) {
293
272
  let sender_bytes32 = address_to_bytes32(sender);
@@ -15,12 +15,12 @@
15
15
  #[cfg(test)]
16
16
  mod tests;
17
17
 
18
- use common_macros::{contract_error, contract_impl};
18
+ use common_macros::contract_error;
19
19
  use endpoint_v2::{
20
20
  FeesAndPacket, IMessageLib, ISendLib, MessageLibType, MessageLibVersion, MessagingFee, OutboundPacket,
21
21
  SetConfigParam,
22
22
  };
23
- use soroban_sdk::{contract, panic_with_error, Address, Bytes, Env, Vec};
23
+ use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, Env, Vec};
24
24
 
25
25
  #[contract_error]
26
26
  pub enum BlockedMessageLibError {
@@ -31,7 +31,7 @@ pub enum BlockedMessageLibError {
31
31
  #[contract]
32
32
  pub struct BlockedMessageLib;
33
33
 
34
- #[contract_impl]
34
+ #[contractimpl]
35
35
  impl IMessageLib for BlockedMessageLib {
36
36
  /// Always panics - config modification is not supported.
37
37
  fn set_config(env: &Env, _oapp: &Address, _param: &Vec<SetConfigParam>) {
@@ -59,7 +59,7 @@ impl IMessageLib for BlockedMessageLib {
59
59
  }
60
60
  }
61
61
 
62
- #[contract_impl]
62
+ #[contractimpl]
63
63
  impl ISendLib for BlockedMessageLib {
64
64
  /// Always panics - quoting is blocked.
65
65
  fn quote(env: &Env, _packet: &OutboundPacket, _options: &Bytes, _pay_in_zro: bool) -> MessagingFee {
@@ -45,7 +45,7 @@ impl ISendLib for Uln302 {
45
45
 
46
46
  // Treasury fee
47
47
  let workers_fee = executor_fee + dvns_fee;
48
- let (_, treasury_fee) = Self::quote_treasury(env, &packet.sender, packet.dst_eid, &workers_fee, &pay_in_zro);
48
+ let (_, treasury_fee) = Self::quote_treasury(env, &packet.sender, packet.dst_eid, workers_fee, pay_in_zro);
49
49
 
50
50
  if pay_in_zro {
51
51
  MessagingFee { native_fee: workers_fee, zro_fee: treasury_fee }
@@ -91,7 +91,7 @@ impl ISendLib for Uln302 {
91
91
  // Treasury fee
92
92
  let total_worker_fee = native_fee_recipients.iter().map(|fee| fee.amount).sum();
93
93
  let (treasury_addr, treasury_fee) =
94
- Self::quote_treasury(env, &packet.sender, packet.dst_eid, &total_worker_fee, &pay_in_zro);
94
+ Self::quote_treasury(env, &packet.sender, packet.dst_eid, total_worker_fee, pay_in_zro);
95
95
 
96
96
  // Handle ZRO fee recipients
97
97
  let mut zro_fee_recipients = vec![env];
@@ -280,12 +280,12 @@ impl Uln302 {
280
280
  env: &Env,
281
281
  sender: &Address,
282
282
  dst_eid: u32,
283
- workers_fee: &i128,
284
- pay_in_zro: &bool,
283
+ workers_fee: i128,
284
+ pay_in_zro: bool,
285
285
  ) -> (Address, i128) {
286
286
  let treasury_addr = Self::treasury(env);
287
287
  let treasury_fee =
288
- LayerZeroTreasuryClient::new(env, &treasury_addr).get_fee(sender, &dst_eid, workers_fee, pay_in_zro);
288
+ LayerZeroTreasuryClient::new(env, &treasury_addr).get_fee(sender, &dst_eid, &workers_fee, &pay_in_zro);
289
289
  assert_with_error!(env, treasury_fee >= 0, Uln302Error::InvalidFee);
290
290
  (treasury_addr, treasury_fee)
291
291
  }
@@ -67,6 +67,12 @@ impl Counter {
67
67
  }
68
68
  }
69
69
 
70
+ #[only_auth]
71
+ pub fn withdraw(env: &Env, to: &Address, amount: i128) {
72
+ let native_token = LayerZeroEndpointV2Client::new(env, &Self::endpoint(env)).native_token();
73
+ TokenClient::new(env, &native_token).transfer(&env.current_contract_address(), to, &amount);
74
+ }
75
+
70
76
  // ============================================================================================
71
77
  // View functions
72
78
  // ============================================================================================
@@ -3,7 +3,7 @@ use crate::{
3
3
  oapp_core::{endpoint_client, get_peer_or_panic, OAppCore},
4
4
  };
5
5
  use endpoint_v2::{MessagingFee, MessagingParams, MessagingReceipt};
6
- use soroban_sdk::{token::TokenClient, Address, Bytes, Env};
6
+ use soroban_sdk::{contracttype, token::TokenClient, Address, Bytes, Env};
7
7
  use utils::option_ext::OptionExt;
8
8
 
9
9
  /// The version of the OAppSender implementation.
@@ -22,7 +22,8 @@ pub const SENDER_VERSION: u64 = 1;
22
22
  /// - `Verified` — Caller asserts that `require_auth()` has already been called.
23
23
  /// Use this to avoid a duplicate `require_auth()` node in the Soroban auth tree
24
24
  /// (e.g., when the same address was already authorized as the message sender).
25
- #[derive(Clone)]
25
+ #[contracttype]
26
+ #[derive(Clone, Debug, Eq, PartialEq)]
26
27
  pub enum FeePayer {
27
28
  /// The fee payer has **not** been authorized yet.
28
29
  /// `__lz_send` will call `fee_payer.require_auth()` before transferring fees.
@@ -8,9 +8,9 @@
8
8
  use crate::integration_tests::{
9
9
  setup::{create_recipient_address, decode_packet, setup, wire_endpoint, wire_oft, TestSetup},
10
10
  utils::{
11
- address_to_peer_bytes32, create_send_param, lz_receive, mint_to, quote_oft, quote_send,
11
+ address_to_peer_bytes32, create_send_param, lz_receive, mint_oft_token_to, mint_to, quote_oft, quote_send,
12
12
  scan_packet_sent_event, send, send_with_fee, set_default_fee_bps, set_fee_bps, set_fee_deposit_address,
13
- token_balance, transfer_sac_admin, validate_packet,
13
+ token_balance, validate_packet,
14
14
  },
15
15
  };
16
16
  use soroban_sdk::{testutils::Address as _, token::TokenClient, Address};
@@ -26,10 +26,8 @@ fn test_cross_chain_with_zero_fee() {
26
26
  let receiver = create_recipient_address(&env);
27
27
  let executor = Address::generate(&env);
28
28
 
29
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 10_000_000);
29
+ mint_oft_token_to(&env, &chain_a, &sender, 10_000_000);
30
30
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
31
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
32
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
33
31
 
34
32
  let to = address_to_peer_bytes32(&receiver);
35
33
  let send_param = create_send_param(&env, chain_b.eid, 1_000_000, 0, &to);
@@ -63,10 +61,8 @@ fn test_cross_chain_with_fee() {
63
61
  let receiver = create_recipient_address(&env);
64
62
  let executor = Address::generate(&env);
65
63
 
66
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 10_000_000);
64
+ mint_oft_token_to(&env, &chain_a, &sender, 10_000_000);
67
65
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
68
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
69
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
70
66
 
71
67
  // Enable 1% fee (100 bps)
72
68
  set_fee_deposit_address(&env, &chain_a, &chain_a.fee_collector);
@@ -116,10 +112,8 @@ fn test_cross_chain_with_destination_specific_fee() {
116
112
  let receiver = create_recipient_address(&env);
117
113
  let executor = Address::generate(&env);
118
114
 
119
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 10_000_000);
115
+ mint_oft_token_to(&env, &chain_a, &sender, 10_000_000);
120
116
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
121
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
122
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
123
117
 
124
118
  // Set default fee 1% and destination-specific fee 2% for chain_b
125
119
  set_fee_deposit_address(&env, &chain_a, &chain_a.fee_collector);
@@ -6,8 +6,8 @@
6
6
  use crate::integration_tests::{
7
7
  setup::{create_recipient_address, decode_packet, setup, wire_endpoint, wire_oft, TestSetup},
8
8
  utils::{
9
- address_to_peer_bytes32, create_send_param, is_paused, lz_receive, mint_to, quote_oft, quote_send,
10
- scan_packet_sent_event, send, set_paused, transfer_sac_admin, try_lz_receive, try_send, validate_packet,
9
+ address_to_peer_bytes32, create_send_param, is_paused, lz_receive, mint_oft_token_to, mint_to, quote_oft,
10
+ quote_send, scan_packet_sent_event, send, set_paused, try_lz_receive, try_send, validate_packet,
11
11
  },
12
12
  };
13
13
  use soroban_sdk::{testutils::Address as _, token::TokenClient, Address};
@@ -22,11 +22,9 @@ fn test_send_succeeds_when_unpaused() {
22
22
  let sender = Address::generate(&env);
23
23
  let receiver = create_recipient_address(&env);
24
24
 
25
- // Mint tokens and transfer admin rights
26
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 10_000_000);
25
+ // Mint tokens (SAC admin is already the mock wrapper from setup)
26
+ mint_oft_token_to(&env, &chain_a, &sender, 10_000_000);
27
27
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
28
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
29
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
30
28
 
31
29
  // Default state should be unpaused
32
30
  assert!(!is_paused(&chain_a));
@@ -63,9 +61,8 @@ fn test_send_fails_when_paused() {
63
61
  let sender = Address::generate(&env);
64
62
  let receiver = create_recipient_address(&env);
65
63
 
66
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 10_000_000);
64
+ mint_oft_token_to(&env, &chain_a, &sender, 10_000_000);
67
65
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
68
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
69
66
 
70
67
  let to = address_to_peer_bytes32(&receiver);
71
68
  let send_param = create_send_param(&env, chain_b.eid, 1_000_000, 0, &to);
@@ -94,10 +91,8 @@ fn test_receive_fails_when_paused() {
94
91
  let receiver = create_recipient_address(&env);
95
92
  let executor = Address::generate(&env);
96
93
 
97
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 10_000_000);
94
+ mint_oft_token_to(&env, &chain_a, &sender, 10_000_000);
98
95
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
99
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
100
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
101
96
 
102
97
  // Send from chain_a to chain_b
103
98
  let to = address_to_peer_bytes32(&receiver);
@@ -130,10 +125,8 @@ fn test_cross_chain_succeeds_after_unpause() {
130
125
  let receiver = create_recipient_address(&env);
131
126
  let executor = Address::generate(&env);
132
127
 
133
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 10_000_000);
128
+ mint_oft_token_to(&env, &chain_a, &sender, 10_000_000);
134
129
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
135
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
136
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
137
130
 
138
131
  // Pause and then unpause
139
132
  set_paused(&env, &chain_a, true);
@@ -7,9 +7,9 @@ use crate::extensions::rate_limiter::{Direction, Mode};
7
7
  use crate::integration_tests::{
8
8
  setup::{create_recipient_address, decode_packet, setup, wire_endpoint, wire_oft, TestSetup},
9
9
  utils::{
10
- address_to_peer_bytes32, advance_time, create_send_param, lz_receive, mint_to, quote_oft, quote_send,
11
- rate_limit_capacity, rate_limit_in_flight, scan_packet_sent_event, send, set_rate_limit, set_rate_limit_with_mode,
12
- transfer_sac_admin, try_send, validate_packet,
10
+ address_to_peer_bytes32, advance_time, create_send_param, lz_receive, mint_oft_token_to, mint_to, quote_oft,
11
+ quote_send, rate_limit_capacity, rate_limit_in_flight, scan_packet_sent_event, send, set_rate_limit,
12
+ set_rate_limit_with_mode, try_send, validate_packet,
13
13
  },
14
14
  };
15
15
  use soroban_sdk::{testutils::Address as _, token::TokenClient, Address};
@@ -25,10 +25,8 @@ fn test_send_without_rate_limit() {
25
25
  let receiver = create_recipient_address(&env);
26
26
  let executor = Address::generate(&env);
27
27
 
28
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 100_000_000);
28
+ mint_oft_token_to(&env, &chain_a, &sender, 100_000_000);
29
29
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
30
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
31
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
32
30
 
33
31
  // Default capacity should be i128::MAX (unlimited)
34
32
  let capacity = rate_limit_capacity(&chain_a, &Direction::Outbound, chain_b.eid);
@@ -62,10 +60,8 @@ fn test_send_within_rate_limit() {
62
60
  let receiver = create_recipient_address(&env);
63
61
  let executor = Address::generate(&env);
64
62
 
65
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 100_000_000);
63
+ mint_oft_token_to(&env, &chain_a, &sender, 100_000_000);
66
64
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
67
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
68
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
69
65
 
70
66
  // Set rate limit: 10M per 3600 seconds (1 hour)
71
67
  set_rate_limit(&env, &chain_a, &Direction::Outbound, chain_b.eid, 10_000_000, 3600);
@@ -112,9 +108,8 @@ fn test_send_exceeds_rate_limit() {
112
108
  let sender = Address::generate(&env);
113
109
  let receiver = create_recipient_address(&env);
114
110
 
115
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 100_000_000);
111
+ mint_oft_token_to(&env, &chain_a, &sender, 100_000_000);
116
112
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
117
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
118
113
 
119
114
  // Set rate limit: 1M per 3600 seconds
120
115
  set_rate_limit(&env, &chain_a, &Direction::Outbound, chain_b.eid, 1_000_000, 3600);
@@ -140,10 +135,8 @@ fn test_rate_limit_decay() {
140
135
  let receiver = create_recipient_address(&env);
141
136
  let executor = Address::generate(&env);
142
137
 
143
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender, 100_000_000);
138
+ mint_oft_token_to(&env, &chain_a, &sender, 100_000_000);
144
139
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender, 10_000_000_000);
145
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
146
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
147
140
 
148
141
  // Set rate limit: 10M per 1000 seconds
149
142
  set_rate_limit(&env, &chain_a, &Direction::Outbound, chain_b.eid, 10_000_000, 1000);
@@ -199,12 +192,10 @@ fn test_gross_mode_does_not_release() {
199
192
  let executor = Address::generate(&env);
200
193
 
201
194
  // Setup tokens for both chains
202
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender_a, 100_000_000);
195
+ mint_oft_token_to(&env, &chain_a, &sender_a, 100_000_000);
203
196
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender_a, 10_000_000_000);
204
- mint_to(&env, &chain_b.owner, &chain_b.oft_token, &sender_b, 100_000_000);
197
+ mint_oft_token_to(&env, &chain_b, &sender_b, 100_000_000);
205
198
  mint_to(&env, &chain_b.owner, &chain_b.native_token, &sender_b, 10_000_000_000);
206
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
207
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
208
199
 
209
200
  // Set Gross mode rate limit on chain_a outbound: 10M per 3600 seconds
210
201
  set_rate_limit_with_mode(&env, &chain_a, &Direction::Outbound, chain_b.eid, 10_000_000, 3600, Mode::Gross);
@@ -267,12 +258,10 @@ fn test_net_mode_does_release() {
267
258
  let executor = Address::generate(&env);
268
259
 
269
260
  // Setup tokens for both chains
270
- mint_to(&env, &chain_a.owner, &chain_a.oft_token, &sender_a, 100_000_000);
261
+ mint_oft_token_to(&env, &chain_a, &sender_a, 100_000_000);
271
262
  mint_to(&env, &chain_a.owner, &chain_a.native_token, &sender_a, 10_000_000_000);
272
- mint_to(&env, &chain_b.owner, &chain_b.oft_token, &sender_b, 100_000_000);
263
+ mint_oft_token_to(&env, &chain_b, &sender_b, 100_000_000);
273
264
  mint_to(&env, &chain_b.owner, &chain_b.native_token, &sender_b, 10_000_000_000);
274
- transfer_sac_admin(&env, &chain_a.owner, &chain_a.oft_token, &chain_a.oft.address);
275
- transfer_sac_admin(&env, &chain_b.owner, &chain_b.oft_token, &chain_b.oft.address);
276
265
 
277
266
  // Set Net mode rate limit on chain_a outbound: 10M per 3600 seconds
278
267
  set_rate_limit_with_mode(&env, &chain_a, &Direction::Outbound, chain_b.eid, 10_000_000, 3600, Mode::Net);
@@ -12,12 +12,40 @@ use crate::{
12
12
  use endpoint_v2::{EndpointV2, EndpointV2Client};
13
13
  use simple_message_lib::{SimpleMessageLib, SimpleMessageLibClient};
14
14
  use soroban_sdk::{
15
- contract, contractimpl, log,
15
+ contract, contractimpl, contracttype, log,
16
16
  testutils::{Address as _, MockAuth, MockAuthInvoke},
17
- token::TokenClient,
17
+ token::{StellarAssetClient, TokenClient},
18
18
  Address, BytesN, Env, IntoVal,
19
19
  };
20
20
 
21
+ // ============================================================================
22
+ // Mock SAC Wrapper - implements Mintable for integration tests
23
+ // ============================================================================
24
+ // Wraps a Stellar Asset Contract (SAC). The wrapper is set as SAC admin and
25
+ // implements mint(env, to, amount, operation) so the OFT uses it for credit (mint).
26
+ // OFT burns on the token directly; this mock still has burn for completeness.
27
+
28
+ #[contracttype]
29
+ pub enum MockSacWrapperKey {
30
+ Sac,
31
+ }
32
+
33
+ #[contract]
34
+ pub struct MockSacWrapper;
35
+
36
+ #[contractimpl]
37
+ impl MockSacWrapper {
38
+ pub fn __constructor(env: &Env, sac: Address) {
39
+ env.storage().instance().set(&MockSacWrapperKey::Sac, &sac);
40
+ }
41
+
42
+ /// Mintable::mint - mints on the underlying SAC (wrapper must be SAC admin).
43
+ pub fn mint(env: &Env, to: &Address, amount: i128, _operation: &Address) {
44
+ let sac: Address = env.storage().instance().get(&MockSacWrapperKey::Sac).unwrap();
45
+ StellarAssetClient::new(env, &sac).mint(to, &amount);
46
+ }
47
+ }
48
+
21
49
  // ============================================================================
22
50
  // Dummy Recipient - used to create valid contract addresses for recipients
23
51
  // ============================================================================
@@ -45,7 +73,10 @@ pub struct ChainSetup<'a> {
45
73
  pub owner: Address,
46
74
  pub native_token: Address,
47
75
  pub zro_token: Address,
76
+ /// Underlying SAC for the OFT token (used for balance, transfer, mint_to).
48
77
  pub oft_token: Address,
78
+ /// Mock SAC wrapper implementing Mintable; OFT uses it for mint on credit.
79
+ pub sac_wrapper: Address,
49
80
  pub endpoint: EndpointV2Client<'a>,
50
81
  pub sml: SimpleMessageLibClient<'a>,
51
82
  pub oft: OFTClient<'a>,
@@ -72,9 +103,20 @@ fn setup_chain<'a>(env: &Env) -> ChainSetup<'a> {
72
103
  let zro_sac = env.register_stellar_asset_contract_v2(owner.clone());
73
104
  let zro_token = zro_sac.address();
74
105
 
75
- // Create OFT token
106
+ // Create OFT token (SAC) and a mock SAC wrapper that implements Mintable.
76
107
  let oft_sac = env.register_stellar_asset_contract_v2(owner.clone());
77
108
  let oft_token = oft_sac.address();
109
+ let sac_wrapper_address = env.register(MockSacWrapper, (&oft_token,));
110
+ env.mock_auths(&[MockAuth {
111
+ address: &owner,
112
+ invoke: &MockAuthInvoke {
113
+ contract: &oft_token,
114
+ fn_name: "set_admin",
115
+ args: (&sac_wrapper_address,).into_val(env),
116
+ sub_invokes: &[],
117
+ },
118
+ }]);
119
+ StellarAssetClient::new(env, &oft_token).set_admin(&sac_wrapper_address);
78
120
 
79
121
  let eid: u32 = 30400; // Test EID
80
122
  let endpoint_address = env.register(EndpointV2, (&owner, eid, &native_token));
@@ -82,9 +124,8 @@ fn setup_chain<'a>(env: &Env) -> ChainSetup<'a> {
82
124
  let sml_address = env.register(SimpleMessageLib, (&owner, &endpoint_address, &fee_recipient));
83
125
  let delegate: Option<Address> = Some(owner.clone());
84
126
  let shared_decimals: u32 = 6; // Default shared decimals
85
- // Both chains use MintBurn the SAC itself implements mint/burn.
86
- // This exercises the MintBurnableClient code path.
87
- let mode = OftType::MintBurn(oft_token.clone());
127
+ // MintBurn with SAC wrapper: OFT uses wrapper for mint on credit; burn is on token directly.
128
+ let mode = OftType::MintBurn(sac_wrapper_address.clone());
88
129
  let oft_address = env.register(OFT, (&oft_token, &shared_decimals, &mode, &owner, &endpoint_address, &delegate));
89
130
 
90
131
  let endpoint = EndpointV2Client::new(env, &endpoint_address);
@@ -104,7 +145,18 @@ fn setup_chain<'a>(env: &Env) -> ChainSetup<'a> {
104
145
  endpoint.set_zro(&zro_token);
105
146
 
106
147
  register_library(env, &owner, &endpoint, &sml.address);
107
- ChainSetup { eid, owner, native_token, zro_token, oft_token, endpoint, sml, oft, fee_collector }
148
+ ChainSetup {
149
+ eid,
150
+ owner,
151
+ native_token,
152
+ zro_token,
153
+ oft_token,
154
+ sac_wrapper: sac_wrapper_address,
155
+ endpoint,
156
+ sml,
157
+ oft,
158
+ fee_collector,
159
+ }
108
160
  }
109
161
 
110
162
  pub fn setup<'a>() -> TestSetup<'a> {