@layerzerolabs/oft-core-stellar-contracts 0.2.122

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.
@@ -0,0 +1,324 @@
1
+ //! Tests for the OApp Message Inspector feature.
2
+
3
+ use crate::tests::test_utils::{create_send_param, OFTTestSetup};
4
+ use common_macros::contract_error;
5
+ use endpoint_v2::MessagingFee;
6
+ use oapp::IOAppMsgInspector;
7
+ use soroban_sdk::{
8
+ contract, contractimpl, panic_with_error,
9
+ testutils::{Address as _, MockAuth, MockAuthInvoke},
10
+ Address, Bytes, BytesN, Env, IntoVal,
11
+ };
12
+
13
+ // ==================== Mock Inspector Contracts ====================
14
+
15
+ /// A mock inspector that always passes (does nothing)
16
+ #[contract]
17
+ pub struct PassingInspector;
18
+
19
+ #[contractimpl]
20
+ impl IOAppMsgInspector for PassingInspector {
21
+ fn inspect(_env: &Env, _oapp: &Address, _message: &Bytes, _options: &Bytes) -> bool {
22
+ // Do nothing - inspection passes
23
+ true
24
+ }
25
+ }
26
+
27
+ #[contract_error]
28
+ pub enum InspectorError {
29
+ InspectionFailed = 1,
30
+ }
31
+
32
+ /// A mock inspector that always fails (panics)
33
+ #[contract]
34
+ pub struct FailingInspector;
35
+
36
+ #[contractimpl]
37
+ impl IOAppMsgInspector for FailingInspector {
38
+ fn inspect(env: &Env, _oapp: &Address, _message: &Bytes, _options: &Bytes) -> bool {
39
+ panic_with_error!(env, InspectorError::InspectionFailed);
40
+ }
41
+ }
42
+
43
+ // ==================== Storage Tests ====================
44
+
45
+ #[test]
46
+ fn test_msg_inspector_not_set_by_default() {
47
+ let env = Env::default();
48
+ let setup = OFTTestSetup::new(&env);
49
+
50
+ // msg_inspector should be None by default
51
+ let inspector = setup.oft.msg_inspector();
52
+ assert_eq!(inspector, None);
53
+ }
54
+
55
+ #[test]
56
+ fn test_set_msg_inspector() {
57
+ let env = Env::default();
58
+ let setup = OFTTestSetup::new(&env);
59
+
60
+ // Deploy a passing inspector
61
+ let inspector_address = env.register(PassingInspector, ());
62
+
63
+ // Owner (authorizer) sets the inspector
64
+ env.mock_auths(&[MockAuth {
65
+ address: &setup.owner,
66
+ invoke: &MockAuthInvoke {
67
+ contract: &setup.oft.address,
68
+ fn_name: "set_msg_inspector",
69
+ args: (&Some(inspector_address.clone()), &setup.owner).into_val(&env),
70
+ sub_invokes: &[],
71
+ },
72
+ }]);
73
+ setup.oft.set_msg_inspector(&Some(inspector_address.clone()), &setup.owner);
74
+
75
+ // Verify inspector is set
76
+ let stored_inspector = setup.oft.msg_inspector();
77
+ assert_eq!(stored_inspector, Some(inspector_address));
78
+ }
79
+
80
+ #[test]
81
+ fn test_remove_msg_inspector() {
82
+ let env = Env::default();
83
+ let setup = OFTTestSetup::new(&env);
84
+
85
+ // Deploy and set a passing inspector first
86
+ let inspector_address = env.register(PassingInspector, ());
87
+
88
+ env.mock_auths(&[MockAuth {
89
+ address: &setup.owner,
90
+ invoke: &MockAuthInvoke {
91
+ contract: &setup.oft.address,
92
+ fn_name: "set_msg_inspector",
93
+ args: (&Some(inspector_address.clone()), &setup.owner).into_val(&env),
94
+ sub_invokes: &[],
95
+ },
96
+ }]);
97
+ setup.oft.set_msg_inspector(&Some(inspector_address), &setup.owner);
98
+
99
+ // Verify it's set
100
+ assert!(setup.oft.msg_inspector().is_some());
101
+
102
+ // Remove the inspector by setting to None
103
+ env.mock_auths(&[MockAuth {
104
+ address: &setup.owner,
105
+ invoke: &MockAuthInvoke {
106
+ contract: &setup.oft.address,
107
+ fn_name: "set_msg_inspector",
108
+ args: (&None::<Address>, &setup.owner).into_val(&env),
109
+ sub_invokes: &[],
110
+ },
111
+ }]);
112
+ setup.oft.set_msg_inspector(&None, &setup.owner);
113
+
114
+ // Verify inspector is removed
115
+ let stored_inspector = setup.oft.msg_inspector();
116
+ assert_eq!(stored_inspector, None);
117
+ }
118
+
119
+ // ==================== Access Control Tests ====================
120
+
121
+ #[test]
122
+ #[should_panic(expected = "Error(Contract, #1086)")] // RbacError::Unauthorized
123
+ fn test_set_msg_inspector_requires_owner() {
124
+ let env = Env::default();
125
+ let setup = OFTTestSetup::new(&env);
126
+
127
+ // Deploy a passing inspector
128
+ let inspector_address = env.register(PassingInspector, ());
129
+
130
+ // Non-owner (not the authorizer) tries to set the inspector
131
+ let non_owner = Address::generate(&env);
132
+ env.mock_auths(&[MockAuth {
133
+ address: &non_owner,
134
+ invoke: &MockAuthInvoke {
135
+ contract: &setup.oft.address,
136
+ fn_name: "set_msg_inspector",
137
+ args: (&Some(inspector_address.clone()), &non_owner).into_val(&env),
138
+ sub_invokes: &[],
139
+ },
140
+ }]);
141
+
142
+ // This should panic because non_owner is not the authorizer
143
+ setup.oft.set_msg_inspector(&Some(inspector_address), &non_owner);
144
+ }
145
+
146
+ // ==================== Integration Tests with Send ====================
147
+
148
+ #[test]
149
+ fn test_send_without_inspector_succeeds() {
150
+ let env = Env::default();
151
+ let setup = OFTTestSetup::new(&env);
152
+
153
+ let sender = Address::generate(&env);
154
+
155
+ // Set peer
156
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
157
+ let dst_eid = 100u32;
158
+ setup.set_peer(dst_eid, &peer);
159
+
160
+ let amount_ld = 12345670i128;
161
+ setup.fund_tokens(&sender, amount_ld);
162
+ setup.fund_native_fees(&sender, setup.native_fee);
163
+
164
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
165
+ let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
166
+ let oft_receipt = setup.quote_oft(&sender, &send_param);
167
+
168
+ // Send without inspector set - should succeed
169
+ let (msg_receipt, oft_receipt) = setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
170
+
171
+ assert!(msg_receipt.nonce > 0);
172
+ assert_eq!(oft_receipt.amount_sent_ld, amount_ld);
173
+ }
174
+
175
+ #[test]
176
+ fn test_send_with_passing_inspector() {
177
+ let env = Env::default();
178
+ let setup = OFTTestSetup::new(&env);
179
+
180
+ // Deploy and set a passing inspector
181
+ let inspector_address = env.register(PassingInspector, ());
182
+ env.mock_auths(&[MockAuth {
183
+ address: &setup.owner,
184
+ invoke: &MockAuthInvoke {
185
+ contract: &setup.oft.address,
186
+ fn_name: "set_msg_inspector",
187
+ args: (&Some(inspector_address.clone()), &setup.owner).into_val(&env),
188
+ sub_invokes: &[],
189
+ },
190
+ }]);
191
+ setup.oft.set_msg_inspector(&Some(inspector_address), &setup.owner);
192
+
193
+ let sender = Address::generate(&env);
194
+
195
+ // Set peer
196
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
197
+ let dst_eid = 100u32;
198
+ setup.set_peer(dst_eid, &peer);
199
+
200
+ let amount_ld = 12345670i128;
201
+ setup.fund_tokens(&sender, amount_ld);
202
+ setup.fund_native_fees(&sender, setup.native_fee);
203
+
204
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
205
+ let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
206
+ let oft_receipt = setup.quote_oft(&sender, &send_param);
207
+
208
+ // Send with passing inspector - should succeed
209
+ let (msg_receipt, oft_receipt) = setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
210
+
211
+ assert!(msg_receipt.nonce > 0);
212
+ assert_eq!(oft_receipt.amount_sent_ld, amount_ld);
213
+ }
214
+
215
+ #[test]
216
+ fn test_send_with_failing_inspector() {
217
+ let env = Env::default();
218
+ let setup = OFTTestSetup::new(&env);
219
+
220
+ // Deploy and set a failing inspector
221
+ let inspector_address = env.register(FailingInspector, ());
222
+ env.mock_auths(&[MockAuth {
223
+ address: &setup.owner,
224
+ invoke: &MockAuthInvoke {
225
+ contract: &setup.oft.address,
226
+ fn_name: "set_msg_inspector",
227
+ args: (&Some(inspector_address.clone()), &setup.owner).into_val(&env),
228
+ sub_invokes: &[],
229
+ },
230
+ }]);
231
+ setup.oft.set_msg_inspector(&Some(inspector_address), &setup.owner);
232
+
233
+ let sender = Address::generate(&env);
234
+
235
+ // Set peer
236
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
237
+ let dst_eid = 100u32;
238
+ setup.set_peer(dst_eid, &peer);
239
+
240
+ let amount_ld = 12345670i128;
241
+ setup.fund_tokens(&sender, amount_ld);
242
+ setup.fund_native_fees(&sender, setup.native_fee);
243
+
244
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
245
+ let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
246
+ let oft_receipt = setup.quote_oft(&sender, &send_param);
247
+
248
+ // Send with failing inspector - should fail
249
+ let result = setup.try_send(&sender, &send_param, &fee, &sender, &oft_receipt);
250
+
251
+ // Verify the send failed due to inspector
252
+ assert!(result.is_err() || result.unwrap().is_err());
253
+ }
254
+
255
+ // ==================== Integration Tests with Quote ====================
256
+
257
+ #[test]
258
+ fn test_quote_send_with_passing_inspector() {
259
+ let env = Env::default();
260
+ let setup = OFTTestSetup::new(&env);
261
+
262
+ // Deploy and set a passing inspector
263
+ let inspector_address = env.register(PassingInspector, ());
264
+ env.mock_auths(&[MockAuth {
265
+ address: &setup.owner,
266
+ invoke: &MockAuthInvoke {
267
+ contract: &setup.oft.address,
268
+ fn_name: "set_msg_inspector",
269
+ args: (&Some(inspector_address.clone()), &setup.owner).into_val(&env),
270
+ sub_invokes: &[],
271
+ },
272
+ }]);
273
+ setup.oft.set_msg_inspector(&Some(inspector_address), &setup.owner);
274
+
275
+ let sender = Address::generate(&env);
276
+
277
+ // Set peer
278
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
279
+ let dst_eid = 100u32;
280
+ setup.set_peer(dst_eid, &peer);
281
+
282
+ let amount_ld = 12345670i128;
283
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
284
+
285
+ // Quote with passing inspector - should succeed
286
+ let fee = setup.oft.quote_send(&sender, &send_param, &false);
287
+
288
+ assert!(fee.native_fee > 0);
289
+ }
290
+
291
+ #[test]
292
+ fn test_quote_send_with_failing_inspector() {
293
+ let env = Env::default();
294
+ let setup = OFTTestSetup::new(&env);
295
+
296
+ // Deploy and set a failing inspector
297
+ let inspector_address = env.register(FailingInspector, ());
298
+ env.mock_auths(&[MockAuth {
299
+ address: &setup.owner,
300
+ invoke: &MockAuthInvoke {
301
+ contract: &setup.oft.address,
302
+ fn_name: "set_msg_inspector",
303
+ args: (&Some(inspector_address.clone()), &setup.owner).into_val(&env),
304
+ sub_invokes: &[],
305
+ },
306
+ }]);
307
+ setup.oft.set_msg_inspector(&Some(inspector_address), &setup.owner);
308
+
309
+ let sender = Address::generate(&env);
310
+
311
+ // Set peer
312
+ let peer = BytesN::from_array(&env, &[2u8; 32]);
313
+ let dst_eid = 100u32;
314
+ setup.set_peer(dst_eid, &peer);
315
+
316
+ let amount_ld = 12345670i128;
317
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
318
+
319
+ // Quote with failing inspector - should fail
320
+ let result = setup.oft.try_quote_send(&sender, &send_param, &false);
321
+
322
+ // Verify the quote failed due to inspector
323
+ assert!(result.is_err());
324
+ }
@@ -0,0 +1,68 @@
1
+ use crate::codec::oft_compose_msg_codec::OFTComposeMsg;
2
+ use soroban_sdk::{Bytes, BytesN, Env};
3
+
4
+ #[test]
5
+ fn test_encode_and_decode_basic() {
6
+ let env = Env::default();
7
+ let nonce = 12345u64;
8
+ let src_eid = 101u32;
9
+ let amount_ld = 1_000_000_000i128; // 1 token with 9 decimals
10
+ let compose_from = BytesN::from_array(&env, &[0x42u8; 32]);
11
+ let compose_msg = Bytes::from_array(&env, b"test compose message");
12
+
13
+ let msg = OFTComposeMsg {
14
+ nonce,
15
+ src_eid,
16
+ amount_ld,
17
+ compose_from: compose_from.clone(),
18
+ compose_msg: compose_msg.clone(),
19
+ };
20
+
21
+ let encoded = msg.encode(&env);
22
+ let decoded = OFTComposeMsg::decode(&encoded);
23
+
24
+ assert_eq!(decoded.nonce, nonce);
25
+ assert_eq!(decoded.src_eid, src_eid);
26
+ assert_eq!(decoded.amount_ld, amount_ld);
27
+ assert_eq!(decoded.compose_from, compose_from);
28
+ assert_eq!(decoded.compose_msg, compose_msg);
29
+ }
30
+
31
+ #[test]
32
+ fn test_encode_with_empty_compose_msg() {
33
+ let env = Env::default();
34
+ let nonce = 123u64;
35
+ let src_eid = 1u32;
36
+ let amount_ld = 1_000_000i128;
37
+ let compose_from = BytesN::from_array(&env, &[0x11u8; 32]);
38
+ let compose_msg = Bytes::new(&env); // Empty
39
+
40
+ let msg = OFTComposeMsg { nonce, src_eid, amount_ld, compose_from: compose_from.clone(), compose_msg };
41
+
42
+ let encoded = msg.encode(&env);
43
+ let decoded = OFTComposeMsg::decode(&encoded);
44
+
45
+ assert_eq!(decoded.nonce, nonce);
46
+ assert_eq!(decoded.src_eid, src_eid);
47
+ assert_eq!(decoded.amount_ld, amount_ld);
48
+ assert_eq!(decoded.compose_from, compose_from);
49
+ assert_eq!(decoded.compose_msg.len(), 0);
50
+ }
51
+
52
+ #[test]
53
+ #[should_panic]
54
+ fn test_decode_panic_on_empty_data() {
55
+ let env = Env::default();
56
+ let data = Bytes::new(&env);
57
+ OFTComposeMsg::decode(&data);
58
+ }
59
+
60
+ #[test]
61
+ #[should_panic]
62
+ fn test_decode_panic_on_insufficient_data() {
63
+ let env = Env::default();
64
+ let mut data = Bytes::new(&env);
65
+ // Only 30 bytes - not enough for nonce(8) + src_eid(4) + amount_ld(16) + compose_from(32) = 60 bytes minimum
66
+ data.extend_from_array(&[0u8; 30]);
67
+ OFTComposeMsg::decode(&data);
68
+ }
@@ -0,0 +1,64 @@
1
+ use crate::codec::oft_msg_codec::{ComposeData, OFTMessage};
2
+ use crate::utils::address_payload;
3
+ use soroban_sdk::{testutils::Address as _, Address, Bytes, BytesN, Env};
4
+
5
+ #[test]
6
+ fn test_encode_and_decode_without_compose() {
7
+ let env = Env::default();
8
+ let send_to_addr = BytesN::from_array(&env, &[1u8; 32]);
9
+ let amount_sd_val = 1000u64;
10
+
11
+ let msg = OFTMessage { send_to: send_to_addr.clone(), amount_sd: amount_sd_val, compose: None };
12
+ let encoded = msg.encode(&env);
13
+
14
+ // Test decode function
15
+ let decoded = OFTMessage::decode(&encoded);
16
+ assert_eq!(decoded.send_to, send_to_addr);
17
+ assert_eq!(decoded.amount_sd, amount_sd_val);
18
+ assert!(decoded.compose.is_none());
19
+ }
20
+
21
+ #[test]
22
+ fn test_encode_and_decode_with_compose() {
23
+ let env = Env::default();
24
+ let sender = Address::generate(&env);
25
+ let send_to_addr = BytesN::from_array(&env, &[2u8; 32]);
26
+ let amount_sd_val = 5000u64;
27
+ let compose_msg_val = Bytes::from_array(&env, &[1u8, 2u8, 3u8, 4u8]);
28
+
29
+ let msg = OFTMessage {
30
+ send_to: send_to_addr.clone(),
31
+ amount_sd: amount_sd_val,
32
+ compose: Some(ComposeData { from: address_payload(&env, &sender), msg: compose_msg_val }),
33
+ };
34
+ let encoded = msg.encode(&env);
35
+
36
+ // Test decode function
37
+ let decoded = OFTMessage::decode(&encoded);
38
+ assert_eq!(decoded.send_to, send_to_addr);
39
+ assert_eq!(decoded.amount_sd, amount_sd_val);
40
+ let compose = decoded.compose.as_ref().unwrap();
41
+ assert_eq!(compose.msg.len(), 4);
42
+
43
+ // Verify compose message structure: sender's bytes32 (32 bytes) + compose_msg (4 bytes)
44
+ let compose_from_len = compose.from.to_array().len() as u32;
45
+ let compose_msg_len = compose.msg.len();
46
+ assert_eq!(compose_from_len + compose_msg_len, 36);
47
+ }
48
+
49
+ #[test]
50
+ #[should_panic]
51
+ fn test_decode_panic_on_empty_data() {
52
+ let env = Env::default();
53
+ let data = Bytes::new(&env);
54
+ OFTMessage::decode(&data);
55
+ }
56
+
57
+ #[test]
58
+ #[should_panic]
59
+ fn test_decode_panic_on_insufficient_data() {
60
+ let env = Env::default();
61
+ let mut data = Bytes::new(&env);
62
+ data.extend_from_array(&[0u8; 20]); // Not enough data for amount_sd
63
+ OFTMessage::decode(&data);
64
+ }
@@ -0,0 +1,22 @@
1
+ use soroban_sdk::Env;
2
+
3
+ use super::test_utils::OFTTestSetup;
4
+
5
+ #[test]
6
+ fn test_oft_version_returns_correct_values() {
7
+ let env = Env::default();
8
+ let setup = OFTTestSetup::new(&env);
9
+
10
+ let (major, minor) = setup.oft.oft_version();
11
+ assert_eq!(major, 1);
12
+ assert_eq!(minor, 1);
13
+ }
14
+
15
+ #[test]
16
+ fn test_approval_required_returns_false_by_default() {
17
+ let env = Env::default();
18
+ let setup = OFTTestSetup::new(&env);
19
+
20
+ // Default OFTCore behavior: no separate token approval is required.
21
+ assert!(!setup.oft.approval_required());
22
+ }
@@ -0,0 +1,159 @@
1
+ use crate::errors::OFTError;
2
+ use soroban_sdk::Env;
3
+
4
+ use super::test_utils::{create_send_param, OFTTestSetup};
5
+
6
+ // ==================== Basic Quote OFT Tests ====================
7
+
8
+ #[test]
9
+ fn test_quote_oft_basic() {
10
+ let env = Env::default();
11
+ let setup = OFTTestSetup::new(&env);
12
+
13
+ let conversion_rate = setup.oft.decimal_conversion_rate();
14
+ let amount_ld = 12345670i128;
15
+ let dust_removed = (amount_ld / conversion_rate) * conversion_rate; // No dust with last digit 0
16
+ let send_param = create_send_param(&env, 1, amount_ld, dust_removed);
17
+
18
+ let (limit, fees, receipt) = setup.oft.quote_oft(&setup.owner, &send_param);
19
+
20
+ // Check limits
21
+ assert_eq!(limit.min_amount_ld, 0);
22
+ assert_eq!(limit.max_amount_ld, u64::MAX as i128);
23
+
24
+ // Check fees (should be empty for basic OFT)
25
+ assert_eq!(fees.len(), 0);
26
+
27
+ // Check receipt
28
+ assert_eq!(receipt.amount_sent_ld, dust_removed);
29
+ assert_eq!(receipt.amount_received_ld, dust_removed);
30
+ }
31
+
32
+ #[test]
33
+ fn test_quote_oft_with_dust_removal() {
34
+ let env = Env::default();
35
+ let setup = OFTTestSetup::new(&env);
36
+
37
+ let conversion_rate = setup.oft.decimal_conversion_rate();
38
+ // Amount with dust that will be removed
39
+ let amount_ld = 12345678i128;
40
+ let dust_removed = (amount_ld / conversion_rate) * conversion_rate;
41
+ let send_param = create_send_param(&env, 1, amount_ld, dust_removed);
42
+
43
+ let (limit, fees, receipt) = setup.oft.quote_oft(&setup.owner, &send_param);
44
+
45
+ // Check limits
46
+ assert_eq!(limit.min_amount_ld, 0);
47
+ assert_eq!(limit.max_amount_ld, u64::MAX as i128);
48
+
49
+ // Check fees (should be empty for basic OFT)
50
+ assert_eq!(fees.len(), 0);
51
+
52
+ // Check receipt - dust removed
53
+ assert_eq!(receipt.amount_sent_ld, dust_removed);
54
+ assert_eq!(receipt.amount_received_ld, dust_removed);
55
+ }
56
+
57
+ #[test]
58
+ fn test_quote_oft_zero_amount() {
59
+ let env = Env::default();
60
+ let setup = OFTTestSetup::new(&env);
61
+
62
+ let send_param = create_send_param(&env, 1, 0, 0);
63
+
64
+ let (limit, fees, receipt) = setup.oft.quote_oft(&setup.owner, &send_param);
65
+
66
+ assert_eq!(receipt.amount_sent_ld, 0);
67
+ assert_eq!(receipt.amount_received_ld, 0);
68
+ assert_eq!(limit.min_amount_ld, 0);
69
+ assert_eq!(limit.max_amount_ld, u64::MAX as i128);
70
+ assert_eq!(fees.len(), 0);
71
+ }
72
+
73
+ #[test]
74
+ fn test_quote_oft_dust_only_amount() {
75
+ let env = Env::default();
76
+ let setup = OFTTestSetup::new(&env);
77
+
78
+ let conversion_rate = setup.oft.decimal_conversion_rate();
79
+ // Amount that is entirely dust (less than conversion rate)
80
+ let amount_ld = conversion_rate - 1; // Less than conversion rate
81
+ let send_param = create_send_param(&env, 1, amount_ld, 0);
82
+
83
+ let (_, _, receipt) = setup.oft.quote_oft(&setup.owner, &send_param);
84
+
85
+ // All dust should be removed
86
+ assert_eq!(receipt.amount_sent_ld, 0);
87
+ assert_eq!(receipt.amount_received_ld, 0);
88
+ }
89
+
90
+ #[test]
91
+ fn test_quote_oft_different_dst_eids() {
92
+ let env = Env::default();
93
+ let setup = OFTTestSetup::new(&env);
94
+
95
+ let amount_ld = 12345670i128; // No dust
96
+
97
+ // Test with different destination EIDs
98
+ for dst_eid in [1u32, 100, 10000, u32::MAX] {
99
+ let send_param = create_send_param(&env, dst_eid, amount_ld, amount_ld);
100
+ let (limit, fees, receipt) = setup.oft.quote_oft(&setup.owner, &send_param);
101
+
102
+ // Results should be the same regardless of dst_eid
103
+ assert_eq!(limit.min_amount_ld, 0);
104
+ assert_eq!(limit.max_amount_ld, u64::MAX as i128);
105
+ assert_eq!(fees.len(), 0);
106
+ assert_eq!(receipt.amount_sent_ld, amount_ld);
107
+ assert_eq!(receipt.amount_received_ld, amount_ld);
108
+ }
109
+ }
110
+
111
+ #[test]
112
+ fn test_quote_oft_large_amounts() {
113
+ let env = Env::default();
114
+ let setup = OFTTestSetup::new(&env);
115
+
116
+ // Test with a large amount
117
+ let amount_ld = 1_000_000_000_000_000_000i128;
118
+ let send_param = create_send_param(&env, 1, amount_ld, amount_ld);
119
+
120
+ let (limit, fees, receipt) = setup.oft.quote_oft(&setup.owner, &send_param);
121
+
122
+ assert_eq!(limit.min_amount_ld, 0);
123
+ assert_eq!(limit.max_amount_ld, u64::MAX as i128);
124
+ assert_eq!(fees.len(), 0);
125
+ assert_eq!(receipt.amount_sent_ld, amount_ld);
126
+ assert_eq!(receipt.amount_received_ld, amount_ld);
127
+ }
128
+
129
+ // ==================== Slippage Tests ====================
130
+
131
+ #[test]
132
+ fn test_quote_oft_slippage_less_than_received() {
133
+ let env = Env::default();
134
+ let setup = OFTTestSetup::new(&env);
135
+
136
+ let conversion_rate = setup.oft.decimal_conversion_rate();
137
+ let amount_ld = 12345678i128;
138
+ let dust_removed = (amount_ld / conversion_rate) * conversion_rate;
139
+ // min_amount_ld is less than what will be received
140
+ let send_param = create_send_param(&env, 1, amount_ld, dust_removed - conversion_rate);
141
+
142
+ let (_, _, receipt) = setup.oft.quote_oft(&setup.owner, &send_param);
143
+
144
+ assert_eq!(receipt.amount_sent_ld, dust_removed);
145
+ assert_eq!(receipt.amount_received_ld, dust_removed);
146
+ }
147
+
148
+ #[test]
149
+ fn test_quote_oft_slippage_exceeded() {
150
+ let env = Env::default();
151
+ let setup = OFTTestSetup::new(&env);
152
+
153
+ let amount_ld = 12345678i128;
154
+ // min_amount_ld is higher than what can be received after dust removal
155
+ let send_param = create_send_param(&env, 1, amount_ld, amount_ld);
156
+
157
+ let result = setup.oft.try_quote_oft(&setup.owner, &send_param);
158
+ assert_eq!(result.err().unwrap().ok().unwrap(), OFTError::SlippageExceeded.into());
159
+ }