@layerzerolabs/protocol-stellar-v2 0.2.18 → 0.2.19

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 (138) hide show
  1. package/.turbo/turbo-build.log +275 -248
  2. package/.turbo/turbo-lint.log +52 -58
  3. package/.turbo/turbo-test.log +1224 -1358
  4. package/Cargo.lock +8 -5
  5. package/Cargo.toml +1 -1
  6. package/contracts/ERROR_SPEC.md +1 -1
  7. package/contracts/message-libs/uln-302/src/send_uln.rs +1 -1
  8. package/contracts/oapps/oapp/src/oapp_receiver.rs +1 -1
  9. package/contracts/oapps/oft/Cargo.toml +10 -7
  10. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_oft_fee.rs +3 -4
  11. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_pausable.rs +2 -3
  12. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_rate_limiter.rs +1 -1
  13. package/contracts/oapps/oft/integration-tests/mod.rs +1 -1
  14. package/contracts/oapps/oft/integration-tests/setup.rs +28 -127
  15. package/contracts/oapps/oft/integration-tests/utils.rs +254 -21
  16. package/contracts/oapps/oft/src/extensions/oft_fee.rs +5 -6
  17. package/contracts/oapps/oft/src/lib.rs +10 -14
  18. package/contracts/oapps/oft/src/oft.rs +151 -189
  19. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +9 -11
  20. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +32 -12
  21. package/contracts/oapps/oft/src/oft_types/mod.rs +13 -0
  22. package/contracts/oapps/{oft-std → oft-core}/Cargo.toml +6 -4
  23. package/contracts/oapps/{oft-std → oft-core}/integration-tests/mod.rs +1 -1
  24. package/contracts/oapps/{oft-std → oft-core}/integration-tests/setup.rs +126 -29
  25. package/contracts/oapps/{oft → oft-core}/integration-tests/test_with_sml.rs +3 -3
  26. package/contracts/oapps/oft-core/integration-tests/utils.rs +201 -0
  27. package/contracts/oapps/oft-core/src/lib.rs +18 -0
  28. package/contracts/oapps/oft-core/src/oft_core.rs +439 -0
  29. package/contracts/oapps/{oft → oft-core}/src/tests/mod.rs +0 -2
  30. package/contracts/oapps/{oft → oft-core}/src/tests/test_lz_receive.rs +7 -7
  31. package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_msg_codec.rs +4 -4
  32. package/contracts/oapps/{oft → oft-core}/src/tests/test_resolve_address.rs +3 -3
  33. package/contracts/oapps/{oft → oft-core}/src/tests/test_utils.rs +44 -25
  34. package/contracts/oapps/{oft → oft-core}/src/utils.rs +1 -1
  35. package/contracts/utils/src/errors.rs +5 -1
  36. package/contracts/utils/src/ownable.rs +125 -3
  37. package/contracts/utils/src/tests/option_ext.rs +1 -1
  38. package/contracts/utils/src/tests/ownable.rs +445 -7
  39. package/contracts/utils/src/tests/ttl_configurable.rs +2 -2
  40. package/package.json +4 -5
  41. package/sdk/.turbo/turbo-test.log +216 -206
  42. package/sdk/dist/generated/bml.d.ts +30 -0
  43. package/sdk/dist/generated/bml.js +28 -5
  44. package/sdk/dist/generated/counter.d.ts +122 -2
  45. package/sdk/dist/generated/counter.js +36 -7
  46. package/sdk/dist/generated/dvn.d.ts +30 -0
  47. package/sdk/dist/generated/dvn.js +28 -5
  48. package/sdk/dist/generated/dvn_fee_lib.d.ts +122 -2
  49. package/sdk/dist/generated/dvn_fee_lib.js +36 -7
  50. package/sdk/dist/generated/endpoint.d.ts +122 -2
  51. package/sdk/dist/generated/endpoint.js +36 -7
  52. package/sdk/dist/generated/executor.d.ts +122 -2
  53. package/sdk/dist/generated/executor.js +36 -7
  54. package/sdk/dist/generated/executor_fee_lib.d.ts +122 -2
  55. package/sdk/dist/generated/executor_fee_lib.js +36 -7
  56. package/sdk/dist/generated/executor_helper.d.ts +30 -0
  57. package/sdk/dist/generated/executor_helper.js +28 -5
  58. package/sdk/dist/generated/oft.d.ts +1842 -0
  59. package/sdk/dist/generated/oft.js +345 -0
  60. package/sdk/dist/generated/price_feed.d.ts +122 -2
  61. package/sdk/dist/generated/price_feed.js +36 -7
  62. package/sdk/dist/generated/sml.d.ts +122 -2
  63. package/sdk/dist/generated/sml.js +36 -7
  64. package/sdk/dist/generated/treasury.d.ts +122 -2
  65. package/sdk/dist/generated/treasury.js +36 -7
  66. package/sdk/dist/generated/uln302.d.ts +122 -2
  67. package/sdk/dist/generated/uln302.js +36 -7
  68. package/sdk/dist/generated/upgrader.d.ts +15 -0
  69. package/sdk/dist/generated/upgrader.js +18 -0
  70. package/sdk/dist/index.d.ts +1 -2
  71. package/sdk/dist/index.js +1 -3
  72. package/sdk/package.json +3 -2
  73. package/sdk/src/index.ts +1 -4
  74. package/sdk/test/oft-sml.test.ts +16 -16
  75. package/sdk/turbo.json +8 -0
  76. package/tools/ts-bindings-gen/Cargo.toml +2 -0
  77. package/tools/ts-bindings-gen/src/main.rs +51 -4
  78. package/turbo.json +0 -2
  79. package/contracts/oapps/oft/src/interfaces/mint_burn_token.rs +0 -23
  80. package/contracts/oapps/oft/src/interfaces/mod.rs +0 -3
  81. package/contracts/oapps/oft/src/oft_impl.rs +0 -201
  82. package/contracts/oapps/oft/src/tests/extensions/mod.rs +0 -11
  83. package/contracts/oapps/oft/src/tests/extensions/setup.rs +0 -917
  84. package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +0 -751
  85. package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +0 -434
  86. package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +0 -1080
  87. package/contracts/oapps/oft-std/integration-tests/utils.rs +0 -427
  88. package/contracts/oapps/oft-std/src/lib.rs +0 -16
  89. package/contracts/oapps/oft-std/src/oft.rs +0 -174
  90. package/sdk/dist/generated/oft_std.d.ts +0 -1722
  91. package/sdk/dist/generated/oft_std.js +0 -316
  92. package/sdk/dist/wasm/blocked-message-lib.d.ts +0 -1
  93. package/sdk/dist/wasm/blocked-message-lib.js +0 -2
  94. package/sdk/dist/wasm/counter.d.ts +0 -1
  95. package/sdk/dist/wasm/counter.js +0 -2
  96. package/sdk/dist/wasm/dvn-fee-lib.d.ts +0 -1
  97. package/sdk/dist/wasm/dvn-fee-lib.js +0 -2
  98. package/sdk/dist/wasm/dvn.d.ts +0 -1
  99. package/sdk/dist/wasm/dvn.js +0 -2
  100. package/sdk/dist/wasm/endpoint-v2.d.ts +0 -1
  101. package/sdk/dist/wasm/endpoint-v2.js +0 -2
  102. package/sdk/dist/wasm/executor-fee-lib.d.ts +0 -1
  103. package/sdk/dist/wasm/executor-fee-lib.js +0 -2
  104. package/sdk/dist/wasm/executor-helper.d.ts +0 -1
  105. package/sdk/dist/wasm/executor-helper.js +0 -2
  106. package/sdk/dist/wasm/executor.d.ts +0 -1
  107. package/sdk/dist/wasm/executor.js +0 -2
  108. package/sdk/dist/wasm/layerzero-views.d.ts +0 -1
  109. package/sdk/dist/wasm/layerzero-views.js +0 -2
  110. package/sdk/dist/wasm/oft-std.d.ts +0 -1
  111. package/sdk/dist/wasm/oft-std.js +0 -2
  112. package/sdk/dist/wasm/price-feed.d.ts +0 -1
  113. package/sdk/dist/wasm/price-feed.js +0 -2
  114. package/sdk/dist/wasm/simple-message-lib.d.ts +0 -1
  115. package/sdk/dist/wasm/simple-message-lib.js +0 -2
  116. package/sdk/dist/wasm/treasury.d.ts +0 -1
  117. package/sdk/dist/wasm/treasury.js +0 -2
  118. package/sdk/dist/wasm/uln302.d.ts +0 -1
  119. package/sdk/dist/wasm/uln302.js +0 -2
  120. package/sdk/dist/wasm/upgrader.d.ts +0 -1
  121. package/sdk/dist/wasm/upgrader.js +0 -2
  122. package/sdk/dist/wasm.d.ts +0 -15
  123. package/sdk/dist/wasm.js +0 -15
  124. /package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/mod.rs +0 -0
  125. /package/contracts/oapps/{oft → oft-core}/src/codec/mod.rs +0 -0
  126. /package/contracts/oapps/{oft → oft-core}/src/codec/oft_compose_msg_codec.rs +0 -0
  127. /package/contracts/oapps/{oft → oft-core}/src/codec/oft_msg_codec.rs +0 -0
  128. /package/contracts/oapps/{oft → oft-core}/src/errors.rs +0 -0
  129. /package/contracts/oapps/{oft → oft-core}/src/events.rs +0 -0
  130. /package/contracts/oapps/{oft → oft-core}/src/storage.rs +0 -0
  131. /package/contracts/oapps/{oft → oft-core}/src/tests/test_decimals.rs +0 -0
  132. /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_compose_msg_codec.rs +0 -0
  133. /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_version.rs +0 -0
  134. /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_oft.rs +0 -0
  135. /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_send.rs +0 -0
  136. /package/contracts/oapps/{oft → oft-core}/src/tests/test_send.rs +0 -0
  137. /package/contracts/oapps/{oft → oft-core}/src/tests/test_token.rs +0 -0
  138. /package/contracts/oapps/{oft → oft-core}/src/types.rs +0 -0
@@ -1,751 +0,0 @@
1
- //! Tests for the OFT fee extension functionality.
2
- //!
3
- //! Tests verify:
4
- //! - Fee configuration (default fee, per-destination fee)
5
- //! - Fee calculation in quote_oft
6
- //! - Fee deduction and transfer in send
7
- //! - Fee deposit address configuration
8
-
9
- use crate::{
10
- extensions::oft_fee::OFTFeeError,
11
- tests::test_utils::{create_origin, create_recipient_address, encode_oft_message},
12
- utils::address_to_bytes32,
13
- };
14
- use endpoint_v2::MessagingFee;
15
- use soroban_sdk::{testutils::Address as _, Address, Bytes, BytesN, Env, IntoVal};
16
-
17
- use super::setup::ExtensiveOFTTestSetup;
18
-
19
- // ==================== Default Fee Configuration Tests ====================
20
-
21
- #[test]
22
- fn test_initial_default_fee_is_zero() {
23
- let env = Env::default();
24
- let setup = ExtensiveOFTTestSetup::new(&env);
25
-
26
- assert_eq!(setup.default_fee_bps(), 0);
27
- }
28
-
29
- #[test]
30
- fn test_set_default_fee_bps() {
31
- let env = Env::default();
32
- let setup = ExtensiveOFTTestSetup::new(&env);
33
-
34
- setup.set_default_fee_bps(100); // 1%
35
- assert_eq!(setup.default_fee_bps(), 100);
36
- }
37
-
38
- #[test]
39
- fn test_set_default_fee_bps_max() {
40
- let env = Env::default();
41
- let setup = ExtensiveOFTTestSetup::new(&env);
42
-
43
- // Max fee is 10000 BPS (100%)
44
- setup.set_default_fee_bps(10000);
45
- assert_eq!(setup.default_fee_bps(), 10000);
46
- }
47
-
48
- #[test]
49
- fn test_set_default_fee_bps_exceeds_max() {
50
- let env = Env::default();
51
- let setup = ExtensiveOFTTestSetup::new(&env);
52
-
53
- // Should fail - exceeds 100%
54
- let result = setup.try_set_default_fee_bps(10001);
55
- assert_eq!(result.err().unwrap().ok().unwrap(), OFTFeeError::InvalidFeeBps.into());
56
- }
57
-
58
- #[test]
59
- fn test_set_default_fee_bps_same_value_fails() {
60
- let env = Env::default();
61
- let setup = ExtensiveOFTTestSetup::new(&env);
62
-
63
- setup.set_default_fee_bps(100);
64
- // Setting same value should fail
65
- let result = setup.try_set_default_fee_bps(100);
66
- assert_eq!(result.err().unwrap().ok().unwrap(), OFTFeeError::SameValue.into());
67
- }
68
-
69
- // ==================== Destination Fee Configuration Tests ====================
70
-
71
- #[test]
72
- fn test_set_fee_bps_for_destination() {
73
- let env = Env::default();
74
- let setup = ExtensiveOFTTestSetup::new(&env);
75
-
76
- let dst_eid = 100u32;
77
- setup.set_fee_bps(dst_eid, 200); // 2%
78
-
79
- assert!(setup.has_fee_bps(dst_eid));
80
- assert_eq!(setup.fee_bps(dst_eid), 200);
81
- }
82
-
83
- #[test]
84
- fn test_set_fee_bps_max_value() {
85
- let env = Env::default();
86
- let setup = ExtensiveOFTTestSetup::new(&env);
87
-
88
- let dst_eid = 100u32;
89
-
90
- // Set max fee (100%)
91
- setup.set_fee_bps(dst_eid, 10000);
92
- assert_eq!(setup.fee_bps(dst_eid), 10000);
93
- }
94
-
95
- #[test]
96
- fn test_set_fee_bps_exceeds_max() {
97
- let env = Env::default();
98
- let setup = ExtensiveOFTTestSetup::new(&env);
99
-
100
- let dst_eid = 100u32;
101
-
102
- // Try to set fee > 100% (> 10000 BPS)
103
- let result = setup.try_set_fee_bps(dst_eid, 10001);
104
- assert_eq!(result.err().unwrap().ok().unwrap(), OFTFeeError::InvalidFeeBps.into());
105
- }
106
-
107
- #[test]
108
- fn test_set_fee_bps_same_value_for_destination_fails() {
109
- let env = Env::default();
110
- let setup = ExtensiveOFTTestSetup::new(&env);
111
-
112
- let dst_eid = 100u32;
113
- let fee_bps = 200u64; // 2%
114
-
115
- // Set fee for destination
116
- setup.set_fee_bps(dst_eid, fee_bps);
117
- assert_eq!(setup.fee_bps(dst_eid), fee_bps);
118
-
119
- // Try to set same fee again - should fail with SameValue
120
- let result = setup.try_set_fee_bps(dst_eid, fee_bps);
121
- assert_eq!(result.err().unwrap().ok().unwrap(), OFTFeeError::SameValue.into());
122
- }
123
-
124
- #[test]
125
- fn test_update_fee_bps_for_destination() {
126
- let env = Env::default();
127
- let setup = ExtensiveOFTTestSetup::new(&env);
128
-
129
- let dst_eid = 100u32;
130
-
131
- // Set initial fee
132
- setup.set_fee_bps(dst_eid, 100);
133
- assert_eq!(setup.fee_bps(dst_eid), 100);
134
-
135
- // Update to different fee
136
- setup.set_fee_bps(dst_eid, 200);
137
- assert_eq!(setup.fee_bps(dst_eid), 200);
138
- }
139
-
140
- #[test]
141
- fn test_unset_fee_bps() {
142
- let env = Env::default();
143
- let setup = ExtensiveOFTTestSetup::new(&env);
144
-
145
- let dst_eid = 100u32;
146
- setup.set_fee_bps(dst_eid, 200);
147
- assert!(setup.has_fee_bps(dst_eid));
148
-
149
- setup.unset_fee_bps(dst_eid);
150
- assert!(!setup.has_fee_bps(dst_eid));
151
- }
152
-
153
- #[test]
154
- fn test_unset_fee_bps_not_found() {
155
- let env = Env::default();
156
- let setup = ExtensiveOFTTestSetup::new(&env);
157
-
158
- let dst_eid = 100u32;
159
-
160
- // Try to unset fee for destination that doesn't have one - should fail with NotFound
161
- let result = setup.try_unset_fee_bps(dst_eid);
162
- assert_eq!(result.err().unwrap().ok().unwrap(), OFTFeeError::NotFound.into());
163
- }
164
-
165
- // ==================== Effective Fee Tests ====================
166
-
167
- #[test]
168
- fn test_has_oft_fee_returns_true_when_fee_configured() {
169
- let env = Env::default();
170
- let setup = ExtensiveOFTTestSetup::new(&env);
171
-
172
- // Initially no fee is configured
173
- let dst_eid = 100u32;
174
- assert_eq!(setup.effective_fee_bps(dst_eid), 0);
175
-
176
- // Set default fee
177
- setup.set_default_fee_bps(100); // 1%
178
-
179
- // Now has_fee_bps should return true since the default fee is non-zero
180
- assert!(setup.has_fee_bps(dst_eid));
181
- }
182
-
183
- #[test]
184
- fn test_has_oft_fee_returns_false_when_no_fee() {
185
- let env = Env::default();
186
- let setup = ExtensiveOFTTestSetup::new(&env);
187
-
188
- let dst_eid = 100u32;
189
-
190
- // No fee configured - should return false
191
- assert!(!setup.has_fee_bps(dst_eid));
192
- }
193
-
194
- #[test]
195
- fn test_has_oft_fee_uses_destination_specific_fee() {
196
- let env = Env::default();
197
- let setup = ExtensiveOFTTestSetup::new(&env);
198
-
199
- let dst_eid_1 = 100u32;
200
- let dst_eid_2 = 200u32;
201
-
202
- // Set destination-specific fee for dst_eid_1 only
203
- setup.set_fee_bps(dst_eid_1, 100); // 1%
204
-
205
- // dst_eid_1 should have fee
206
- assert!(setup.has_fee_bps(dst_eid_1));
207
-
208
- // dst_eid_2 should not have fee (no default, no specific)
209
- assert!(!setup.has_fee_bps(dst_eid_2));
210
- }
211
-
212
- #[test]
213
- fn test_effective_fee_uses_destination_over_default() {
214
- let env = Env::default();
215
- let setup = ExtensiveOFTTestSetup::new(&env);
216
-
217
- setup.set_default_fee_bps(100); // 1% default
218
-
219
- let dst_eid = 100u32;
220
- setup.set_fee_bps(dst_eid, 200); // 2% for specific destination
221
-
222
- // Effective fee should use destination-specific fee
223
- assert_eq!(setup.effective_fee_bps(dst_eid), 200);
224
- }
225
-
226
- #[test]
227
- fn test_effective_fee_falls_back_to_default() {
228
- let env = Env::default();
229
- let setup = ExtensiveOFTTestSetup::new(&env);
230
-
231
- setup.set_default_fee_bps(100); // 1% default
232
-
233
- let dst_eid = 100u32;
234
- // No destination-specific fee set
235
-
236
- // Effective fee should use default
237
- assert_eq!(setup.effective_fee_bps(dst_eid), 100);
238
- }
239
-
240
- // ==================== Fee Deposit Address Tests ====================
241
-
242
- #[test]
243
- fn test_set_fee_deposit_address() {
244
- let env = Env::default();
245
- let setup = ExtensiveOFTTestSetup::new(&env);
246
-
247
- let fee_collector = create_recipient_address(&env);
248
- setup.set_fee_deposit_address(&fee_collector);
249
-
250
- assert_eq!(setup.fee_deposit_address(), fee_collector);
251
- }
252
-
253
- #[test]
254
- fn test_set_fee_deposit_address_same_value_fails() {
255
- let env = Env::default();
256
- let setup = ExtensiveOFTTestSetup::new(&env);
257
-
258
- let fee_collector = create_recipient_address(&env);
259
-
260
- // Set fee deposit address
261
- setup.set_fee_deposit_address(&fee_collector);
262
- assert_eq!(setup.fee_deposit_address(), fee_collector);
263
-
264
- // Try to set same address again - should fail with SameValue
265
- let result = setup.try_set_fee_deposit_address(&fee_collector);
266
- assert_eq!(result.err().unwrap().ok().unwrap(), OFTFeeError::SameValue.into());
267
- }
268
-
269
- #[test]
270
- fn test_update_fee_deposit_address() {
271
- let env = Env::default();
272
- let setup = ExtensiveOFTTestSetup::new(&env);
273
-
274
- let fee_collector_1 = create_recipient_address(&env);
275
- let fee_collector_2 = create_recipient_address(&env);
276
-
277
- // Set initial address
278
- setup.set_fee_deposit_address(&fee_collector_1);
279
- assert_eq!(setup.fee_deposit_address(), fee_collector_1);
280
-
281
- // Update to different address
282
- setup.set_fee_deposit_address(&fee_collector_2);
283
- assert_eq!(setup.fee_deposit_address(), fee_collector_2);
284
- }
285
-
286
- // ==================== quote_oft Tests (Fee Calculation) ====================
287
-
288
- #[test]
289
- fn test_quote_oft_no_fee() {
290
- let env = Env::default();
291
- let setup = ExtensiveOFTTestSetup::new(&env);
292
-
293
- // Set fee deposit address (required by ExtensiveOFT even with no fee)
294
- let fee_collector = create_recipient_address(&env);
295
- setup.set_fee_deposit_address(&fee_collector);
296
-
297
- let dst_eid = 100u32;
298
- let peer = BytesN::from_array(&env, &[2u8; 32]);
299
- setup.set_peer(dst_eid, &peer);
300
-
301
- let amount_ld = 1_000_000i128;
302
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
303
-
304
- let receipt = setup.quote_oft(&send_param);
305
-
306
- // No fee configured, amounts should be equal
307
- assert_eq!(receipt.amount_sent_ld, amount_ld);
308
- assert_eq!(receipt.amount_received_ld, amount_ld);
309
- }
310
-
311
- #[test]
312
- fn test_quote_oft_with_default_fee() {
313
- let env = Env::default();
314
- let setup = ExtensiveOFTTestSetup::new(&env);
315
-
316
- // Set fee deposit address (required for fee to be applied)
317
- let fee_collector = create_recipient_address(&env);
318
- setup.set_fee_deposit_address(&fee_collector);
319
-
320
- // Set 1% default fee (100 BPS)
321
- setup.set_default_fee_bps(100);
322
-
323
- let dst_eid = 100u32;
324
- let peer = BytesN::from_array(&env, &[2u8; 32]);
325
- setup.set_peer(dst_eid, &peer);
326
-
327
- let dust = 5i128;
328
- let amount_ld = 1_000_000i128 + dust; // dust will be charged as a fee
329
- // min_amount_ld should account for fee
330
- let expected_after_fee = 990_000i128; // 1% fee
331
- let send_param = setup.create_send_param(dst_eid, amount_ld, expected_after_fee);
332
-
333
- let receipt = setup.quote_oft(&send_param);
334
-
335
- // Amount sent is original, amount received is after fee
336
- assert_eq!(receipt.amount_sent_ld, amount_ld);
337
- assert_eq!(receipt.amount_received_ld, expected_after_fee);
338
- }
339
-
340
- #[test]
341
- fn test_quote_oft_with_destination_fee() {
342
- let env = Env::default();
343
- let setup = ExtensiveOFTTestSetup::new(&env);
344
-
345
- // Set fee deposit address
346
- let fee_collector = create_recipient_address(&env);
347
- setup.set_fee_deposit_address(&fee_collector);
348
-
349
- // Set 1% default fee and 2% for specific destination
350
- setup.set_default_fee_bps(100);
351
- let dst_eid = 100u32;
352
- setup.set_fee_bps(dst_eid, 200); // 2%
353
-
354
- let peer = BytesN::from_array(&env, &[2u8; 32]);
355
- setup.set_peer(dst_eid, &peer);
356
-
357
- let amount_ld = 1_000_000i128;
358
- let expected_after_fee = 980_000i128; // 2% fee
359
- let send_param = setup.create_send_param(dst_eid, amount_ld, expected_after_fee);
360
-
361
- let receipt = setup.quote_oft(&send_param);
362
-
363
- // Should use destination-specific 2% fee
364
- assert_eq!(receipt.amount_sent_ld, amount_ld);
365
- assert_eq!(receipt.amount_received_ld, expected_after_fee);
366
- }
367
-
368
- #[test]
369
- fn test_quote_oft_fee_calculation_precision() {
370
- let env = Env::default();
371
- let setup = ExtensiveOFTTestSetup::new(&env);
372
-
373
- // Set fee deposit address
374
- let fee_collector = create_recipient_address(&env);
375
- setup.set_fee_deposit_address(&fee_collector);
376
-
377
- // Set 0.5% fee (50 BPS)
378
- setup.set_default_fee_bps(50);
379
-
380
- let dst_eid = 100u32;
381
- let peer = BytesN::from_array(&env, &[2u8; 32]);
382
- setup.set_peer(dst_eid, &peer);
383
-
384
- let amount_ld = 1_000_000i128;
385
- // 0.5% of 1_000_000 = 5_000 fee
386
- let expected_after_fee = 995_000i128;
387
- let send_param = setup.create_send_param(dst_eid, amount_ld, expected_after_fee);
388
-
389
- let receipt = setup.quote_oft(&send_param);
390
-
391
- assert_eq!(receipt.amount_sent_ld, amount_ld);
392
- assert_eq!(receipt.amount_received_ld, expected_after_fee);
393
- }
394
-
395
- // ==================== quote_send Tests (Fee) ====================
396
-
397
- #[test]
398
- fn test_quote_send_with_fee() {
399
- let env = Env::default();
400
- let setup = ExtensiveOFTTestSetup::new(&env);
401
-
402
- // Set fee deposit address and fee
403
- let fee_collector = create_recipient_address(&env);
404
- setup.set_fee_deposit_address(&fee_collector);
405
- setup.set_default_fee_bps(100); // 1%
406
-
407
- let sender = Address::generate(&env);
408
- let dst_eid = 100u32;
409
- let peer = BytesN::from_array(&env, &[2u8; 32]);
410
- setup.set_peer(dst_eid, &peer);
411
-
412
- let amount_ld = 1_000_000i128;
413
- let expected_after_fee = 990_000i128;
414
- let send_param = setup.create_send_param(dst_eid, amount_ld, expected_after_fee);
415
-
416
- // quote_send should work with fees configured
417
- let msg_fee = setup.quote_send(&sender, &send_param, false);
418
- assert!(msg_fee.native_fee > 0);
419
- }
420
-
421
- // ==================== send Tests (Fee Transfer) ====================
422
-
423
- #[test]
424
- fn test_quote_oft_with_fee_without_deposit_address_fails() {
425
- let env = Env::default();
426
- let setup = ExtensiveOFTTestSetup::new(&env);
427
-
428
- // Set fee rate but no fee deposit address
429
- setup.set_default_fee_bps(100); // 1%
430
-
431
- let dst_eid = 100u32;
432
- let peer = BytesN::from_array(&env, &[2u8; 32]);
433
- setup.set_peer(dst_eid, &peer);
434
-
435
- let amount_ld = 1_000_000i128;
436
- let expected_after_fee = 990_000i128;
437
- let send_param = setup.create_send_param(dst_eid, amount_ld, expected_after_fee);
438
-
439
- // quote_oft should fail because fee deposit address is not set
440
- let result = setup.try_quote_oft(&send_param);
441
- assert_eq!(result.err().unwrap().ok().unwrap(), OFTFeeError::InvalidFeeDepositAddress.into());
442
- }
443
-
444
- #[test]
445
- fn test_send_with_fee_transfers_to_collector() {
446
- let env = Env::default();
447
- let setup = ExtensiveOFTTestSetup::new(&env);
448
-
449
- // Set fee deposit address
450
- let fee_collector = create_recipient_address(&env);
451
- setup.set_fee_deposit_address(&fee_collector);
452
-
453
- // Set 1% fee
454
- setup.set_default_fee_bps(100);
455
-
456
- let sender = Address::generate(&env);
457
- let dst_eid = 100u32;
458
- let peer = BytesN::from_array(&env, &[2u8; 32]);
459
- setup.set_peer(dst_eid, &peer);
460
-
461
- let amount_ld = 1_000_000i128;
462
- let expected_fee = 10_000i128; // 1%
463
- let expected_after_fee = 990_000i128;
464
-
465
- setup.fund_tokens(&sender, amount_ld);
466
- setup.fund_native_fees(&sender, setup.native_fee);
467
-
468
- let initial_collector_balance = setup.token_client.balance(&fee_collector);
469
-
470
- let send_param = setup.create_send_param(dst_eid, amount_ld, expected_after_fee);
471
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
472
- let oft_receipt = setup.quote_oft(&send_param);
473
-
474
- // Use send_with_fee which includes fee transfer auth
475
- let (_, receipt) = setup.send_with_fee(&sender, &send_param, &fee, &sender, &oft_receipt, &fee_collector);
476
-
477
- // Verify receipt
478
- assert_eq!(receipt.amount_sent_ld, amount_ld);
479
- assert_eq!(receipt.amount_received_ld, expected_after_fee);
480
-
481
- // Verify fee was transferred to collector
482
- assert_eq!(setup.token_client.balance(&fee_collector), initial_collector_balance + expected_fee);
483
-
484
- // Verify sender's tokens were burned (amount_sent_ld)
485
- assert_eq!(setup.token_client.balance(&sender), 0);
486
- }
487
-
488
- #[test]
489
- fn test_send_without_fee_no_transfer() {
490
- let env = Env::default();
491
- let setup = ExtensiveOFTTestSetup::new(&env);
492
-
493
- // Set fee deposit address (required by ExtensiveOFT)
494
- let fee_collector = create_recipient_address(&env);
495
- setup.set_fee_deposit_address(&fee_collector);
496
-
497
- // No fee rate configured (default is 0)
498
- let sender = Address::generate(&env);
499
- let dst_eid = 100u32;
500
- let peer = BytesN::from_array(&env, &[2u8; 32]);
501
- setup.set_peer(dst_eid, &peer);
502
-
503
- let amount_ld = 1_000_000i128;
504
- setup.fund_tokens(&sender, amount_ld);
505
- setup.fund_native_fees(&sender, setup.native_fee);
506
-
507
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
508
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
509
- let oft_receipt = setup.quote_oft(&send_param);
510
-
511
- // Use regular send (no fee transfer needed since fee is 0)
512
- let (_, receipt) = setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
513
-
514
- // Amounts should be equal (no fee)
515
- assert_eq!(receipt.amount_sent_ld, amount_ld);
516
- assert_eq!(receipt.amount_received_ld, amount_ld);
517
- }
518
-
519
- #[test]
520
- fn test_send_with_different_destination_fees() {
521
- let env = Env::default();
522
- let setup = ExtensiveOFTTestSetup::new(&env);
523
-
524
- // Set fee deposit address
525
- let fee_collector = create_recipient_address(&env);
526
- setup.set_fee_deposit_address(&fee_collector);
527
-
528
- // Set different fees for different destinations
529
- let dst_eid_1 = 100u32;
530
- let dst_eid_2 = 200u32;
531
- setup.set_fee_bps(dst_eid_1, 100); // 1%
532
- setup.set_fee_bps(dst_eid_2, 500); // 5%
533
-
534
- let peer = BytesN::from_array(&env, &[2u8; 32]);
535
- setup.set_peer(dst_eid_1, &peer);
536
- setup.set_peer(dst_eid_2, &peer);
537
-
538
- let sender = Address::generate(&env);
539
- let amount_ld = 1_000_000i128;
540
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
541
-
542
- // First send to dst_eid_1 (1% fee)
543
- setup.fund_tokens(&sender, amount_ld);
544
- setup.fund_native_fees(&sender, setup.native_fee);
545
-
546
- let expected_after_fee_1 = 990_000i128;
547
- let send_param_1 = setup.create_send_param(dst_eid_1, amount_ld, expected_after_fee_1);
548
- let oft_receipt_1 = setup.quote_oft(&send_param_1);
549
-
550
- let (_, receipt_1) = setup.send_with_fee(&sender, &send_param_1, &fee, &sender, &oft_receipt_1, &fee_collector);
551
- assert_eq!(receipt_1.amount_received_ld, expected_after_fee_1);
552
-
553
- // Second send to dst_eid_2 (5% fee)
554
- setup.fund_tokens(&sender, amount_ld);
555
- setup.fund_native_fees(&sender, setup.native_fee);
556
-
557
- let expected_after_fee_2 = 950_000i128;
558
- let send_param_2 = setup.create_send_param(dst_eid_2, amount_ld, expected_after_fee_2);
559
- let oft_receipt_2 = setup.quote_oft(&send_param_2);
560
-
561
- let (_, receipt_2) = setup.send_with_fee(&sender, &send_param_2, &fee, &sender, &oft_receipt_2, &fee_collector);
562
- assert_eq!(receipt_2.amount_received_ld, expected_after_fee_2);
563
- }
564
-
565
- // ==================== lz_receive Tests (No Fee on Inbound) ====================
566
-
567
- #[test]
568
- fn test_lz_receive_no_fee_on_inbound() {
569
- let env = Env::default();
570
- let setup = ExtensiveOFTTestSetup::new(&env);
571
-
572
- // Set fee (only applies to outbound)
573
- let fee_collector = create_recipient_address(&env);
574
- setup.set_fee_deposit_address(&fee_collector);
575
- setup.set_default_fee_bps(100); // 1%
576
-
577
- let executor = Address::generate(&env);
578
- let recipient = create_recipient_address(&env);
579
- let src_eid = 100u32;
580
- let peer = BytesN::from_array(&env, &[2u8; 32]);
581
- setup.set_peer(src_eid, &peer);
582
-
583
- let amount_sd = 1_000_000u64;
584
- let recipient_bytes32 = address_to_bytes32(&recipient);
585
- let message = encode_oft_message(&env, &recipient_bytes32, amount_sd);
586
-
587
- let guid = BytesN::from_array(&env, &[1u8; 32]);
588
- let origin = create_origin(src_eid, &peer, 1);
589
- let extra_data = Bytes::new(&env);
590
-
591
- let initial_balance = setup.token_client.balance(&recipient);
592
- let initial_collector_balance = setup.token_client.balance(&fee_collector);
593
-
594
- setup.lz_receive(&executor, &origin, &guid, &message, &extra_data, 0);
595
-
596
- // Recipient should receive full amount (no fee on inbound)
597
- let conversion_rate = setup.oft.decimal_conversion_rate();
598
- let expected_amount_ld = (amount_sd as i128) * conversion_rate;
599
- assert_eq!(setup.token_client.balance(&recipient), initial_balance + expected_amount_ld);
600
-
601
- // Fee collector should not receive anything on inbound
602
- assert_eq!(setup.token_client.balance(&fee_collector), initial_collector_balance);
603
- }
604
-
605
- // ==================== Authentication Tests ====================
606
-
607
- #[test]
608
- fn test_set_default_fee_bps_requires_owner_auth() {
609
- let env = Env::default();
610
- let setup = ExtensiveOFTTestSetup::new(&env);
611
-
612
- // Try to set default fee without auth (no auth provided)
613
- let result = setup.oft.try_set_default_fee_bps(&100);
614
- assert!(result.is_err());
615
- }
616
-
617
- #[test]
618
- fn test_set_default_fee_bps_wrong_auth_fails() {
619
- let env = Env::default();
620
- let setup = ExtensiveOFTTestSetup::new(&env);
621
-
622
- let non_owner = Address::generate(&env);
623
-
624
- // Try to set default fee with wrong auth (non-owner)
625
- env.mock_auths(&[soroban_sdk::testutils::MockAuth {
626
- address: &non_owner,
627
- invoke: &soroban_sdk::testutils::MockAuthInvoke {
628
- contract: &setup.oft.address,
629
- fn_name: "set_default_fee_bps",
630
- args: (100u64,).into_val(&env),
631
- sub_invokes: &[],
632
- },
633
- }]);
634
- let result = setup.oft.try_set_default_fee_bps(&100);
635
- assert!(result.is_err());
636
- }
637
-
638
- #[test]
639
- fn test_set_fee_bps_requires_owner_auth() {
640
- let env = Env::default();
641
- let setup = ExtensiveOFTTestSetup::new(&env);
642
-
643
- let dst_eid = 100u32;
644
-
645
- // Try to set fee bps without auth
646
- let result = setup.oft.try_set_fee_bps(&dst_eid, &200);
647
- assert!(result.is_err());
648
- }
649
-
650
- #[test]
651
- fn test_set_fee_bps_wrong_auth_fails() {
652
- let env = Env::default();
653
- let setup = ExtensiveOFTTestSetup::new(&env);
654
-
655
- let non_owner = Address::generate(&env);
656
- let dst_eid = 100u32;
657
-
658
- // Try to set fee bps with wrong auth (non-owner)
659
- env.mock_auths(&[soroban_sdk::testutils::MockAuth {
660
- address: &non_owner,
661
- invoke: &soroban_sdk::testutils::MockAuthInvoke {
662
- contract: &setup.oft.address,
663
- fn_name: "set_fee_bps",
664
- args: (dst_eid, 200u64).into_val(&env),
665
- sub_invokes: &[],
666
- },
667
- }]);
668
- let result = setup.oft.try_set_fee_bps(&dst_eid, &200);
669
- assert!(result.is_err());
670
- }
671
-
672
- #[test]
673
- fn test_unset_fee_bps_requires_owner_auth() {
674
- let env = Env::default();
675
- let setup = ExtensiveOFTTestSetup::new(&env);
676
-
677
- let dst_eid = 100u32;
678
-
679
- // First set fee bps as owner
680
- setup.set_fee_bps(dst_eid, 200);
681
- assert!(setup.has_fee_bps(dst_eid));
682
-
683
- // Try to unset fee bps without auth
684
- let result = setup.oft.try_unset_fee_bps(&dst_eid);
685
- assert!(result.is_err());
686
-
687
- // Fee should still be set
688
- assert!(setup.has_fee_bps(dst_eid));
689
- }
690
-
691
- #[test]
692
- fn test_unset_fee_bps_wrong_auth_fails() {
693
- let env = Env::default();
694
- let setup = ExtensiveOFTTestSetup::new(&env);
695
-
696
- let non_owner = Address::generate(&env);
697
- let dst_eid = 100u32;
698
-
699
- // First set fee bps as owner
700
- setup.set_fee_bps(dst_eid, 200);
701
-
702
- // Try to unset fee bps with wrong auth (non-owner)
703
- env.mock_auths(&[soroban_sdk::testutils::MockAuth {
704
- address: &non_owner,
705
- invoke: &soroban_sdk::testutils::MockAuthInvoke {
706
- contract: &setup.oft.address,
707
- fn_name: "unset_fee_bps",
708
- args: (dst_eid,).into_val(&env),
709
- sub_invokes: &[],
710
- },
711
- }]);
712
- let result = setup.oft.try_unset_fee_bps(&dst_eid);
713
- assert!(result.is_err());
714
-
715
- // Fee should still be set
716
- assert!(setup.has_fee_bps(dst_eid));
717
- }
718
-
719
- #[test]
720
- fn test_set_fee_deposit_address_requires_owner_auth() {
721
- let env = Env::default();
722
- let setup = ExtensiveOFTTestSetup::new(&env);
723
-
724
- let fee_collector = create_recipient_address(&env);
725
-
726
- // Try to set fee deposit address without auth
727
- let result = setup.oft.try_set_fee_deposit_address(&fee_collector);
728
- assert!(result.is_err());
729
- }
730
-
731
- #[test]
732
- fn test_set_fee_deposit_address_wrong_auth_fails() {
733
- let env = Env::default();
734
- let setup = ExtensiveOFTTestSetup::new(&env);
735
-
736
- let non_owner = Address::generate(&env);
737
- let fee_collector = create_recipient_address(&env);
738
-
739
- // Try to set fee deposit address with wrong auth (non-owner)
740
- env.mock_auths(&[soroban_sdk::testutils::MockAuth {
741
- address: &non_owner,
742
- invoke: &soroban_sdk::testutils::MockAuthInvoke {
743
- contract: &setup.oft.address,
744
- fn_name: "set_fee_deposit_address",
745
- args: (&fee_collector,).into_val(&env),
746
- sub_invokes: &[],
747
- },
748
- }]);
749
- let result = setup.oft.try_set_fee_deposit_address(&fee_collector);
750
- assert!(result.is_err());
751
- }