@layerzerolabs/protocol-stellar-v2 0.2.19 → 0.2.20

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 (125) hide show
  1. package/.turbo/turbo-build.log +245 -222
  2. package/.turbo/turbo-lint.log +77 -70
  3. package/.turbo/turbo-test.log +1385 -1221
  4. package/Cargo.lock +13 -3
  5. package/Cargo.toml +2 -0
  6. package/contracts/ERROR_SPEC.md +8 -1
  7. package/contracts/common-macros/src/contract_ttl.rs +18 -7
  8. package/contracts/common-macros/src/lib.rs +4 -4
  9. package/contracts/common-macros/src/tests/contract_ttl.rs +1 -1
  10. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
  11. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +7 -12
  12. package/contracts/common-macros/src/upgradeable.rs +15 -21
  13. package/contracts/message-libs/uln-302/src/events.rs +4 -0
  14. package/contracts/message-libs/uln-302/src/send_uln.rs +22 -6
  15. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +38 -64
  16. package/contracts/oapps/counter/Cargo.toml +1 -0
  17. package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
  18. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +113 -65
  19. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +111 -82
  20. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +293 -65
  21. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +331 -56
  22. package/contracts/oapps/oft/src/extensions/oft_fee.rs +18 -2
  23. package/contracts/oapps/oft/src/extensions/pausable.rs +19 -4
  24. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +52 -28
  25. package/contracts/oapps/oft/src/oft.rs +29 -41
  26. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +3 -25
  27. package/contracts/oapps/oft-core/integration-tests/setup.rs +2 -2
  28. package/contracts/oapps/oft-core/src/oft_core.rs +247 -207
  29. package/contracts/oapps/oft-core/src/tests/test_utils.rs +4 -4
  30. package/contracts/upgrader/src/lib.rs +30 -57
  31. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
  32. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
  33. package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
  34. package/contracts/utils/src/buffer_reader.rs +1 -0
  35. package/contracts/utils/src/errors.rs +3 -1
  36. package/contracts/utils/src/tests/upgradeable.rs +372 -175
  37. package/contracts/utils/src/ttl_configurable.rs +3 -3
  38. package/contracts/utils/src/upgradeable.rs +48 -23
  39. package/contracts/workers/dvn/Cargo.toml +1 -0
  40. package/contracts/workers/dvn/src/auth.rs +12 -42
  41. package/contracts/workers/dvn/src/dvn.rs +16 -31
  42. package/contracts/workers/dvn/src/errors.rs +0 -1
  43. package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
  44. package/contracts/workers/dvn/src/lib.rs +4 -3
  45. package/contracts/workers/dvn/src/tests/auth.rs +1 -1
  46. package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
  47. package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
  48. package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
  49. package/contracts/workers/dvn/src/tests/setup.rs +5 -9
  50. package/contracts/workers/dvn-fee-lib/Cargo.toml +1 -1
  51. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +3 -5
  52. package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +2 -3
  53. package/contracts/workers/executor/Cargo.toml +1 -0
  54. package/contracts/workers/executor/src/executor.rs +15 -26
  55. package/contracts/workers/executor-fee-lib/Cargo.toml +2 -1
  56. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +63 -5
  57. package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
  58. package/contracts/workers/executor-fee-lib/src/lib.rs +3 -0
  59. package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
  60. package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
  61. package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
  62. package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
  63. package/contracts/workers/executor-helper/src/lib.rs +3 -0
  64. package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
  65. package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
  66. package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
  67. package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
  68. package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
  69. package/contracts/workers/price-feed/Cargo.toml +2 -1
  70. package/contracts/workers/price-feed/src/events.rs +1 -1
  71. package/contracts/workers/price-feed/src/lib.rs +3 -0
  72. package/contracts/workers/price-feed/src/price_feed.rs +6 -12
  73. package/contracts/workers/price-feed/src/storage.rs +1 -1
  74. package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
  75. package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
  76. package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
  77. package/contracts/workers/price-feed/src/types.rs +1 -1
  78. package/contracts/workers/worker/src/errors.rs +0 -3
  79. package/contracts/workers/worker/src/lib.rs +0 -2
  80. package/contracts/workers/worker/src/storage.rs +32 -29
  81. package/contracts/workers/worker/src/tests/setup.rs +1 -7
  82. package/contracts/workers/worker/src/tests/worker.rs +50 -42
  83. package/contracts/workers/worker/src/worker.rs +49 -58
  84. package/package.json +3 -3
  85. package/sdk/.turbo/turbo-test.log +220 -218
  86. package/sdk/dist/generated/bml.d.ts +12 -4
  87. package/sdk/dist/generated/bml.js +8 -6
  88. package/sdk/dist/generated/counter.d.ts +12 -4
  89. package/sdk/dist/generated/counter.js +8 -6
  90. package/sdk/dist/generated/dvn.d.ts +404 -365
  91. package/sdk/dist/generated/dvn.js +55 -53
  92. package/sdk/dist/generated/dvn_fee_lib.d.ts +224 -268
  93. package/sdk/dist/generated/dvn_fee_lib.js +22 -53
  94. package/sdk/dist/generated/endpoint.d.ts +12 -4
  95. package/sdk/dist/generated/endpoint.js +8 -6
  96. package/sdk/dist/generated/executor.d.ts +370 -326
  97. package/sdk/dist/generated/executor.js +47 -44
  98. package/sdk/dist/generated/executor_fee_lib.d.ts +258 -302
  99. package/sdk/dist/generated/executor_fee_lib.js +21 -52
  100. package/sdk/dist/generated/executor_helper.d.ts +26 -190
  101. package/sdk/dist/generated/executor_helper.js +22 -27
  102. package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
  103. package/sdk/dist/generated/layerzero_view.js +294 -0
  104. package/sdk/dist/generated/oft.d.ts +49 -40
  105. package/sdk/dist/generated/oft.js +25 -23
  106. package/sdk/dist/generated/price_feed.d.ts +225 -269
  107. package/sdk/dist/generated/price_feed.js +22 -53
  108. package/sdk/dist/generated/sml.d.ts +12 -4
  109. package/sdk/dist/generated/sml.js +8 -6
  110. package/sdk/dist/generated/treasury.d.ts +12 -4
  111. package/sdk/dist/generated/treasury.js +8 -6
  112. package/sdk/dist/generated/uln302.d.ts +12 -4
  113. package/sdk/dist/generated/uln302.js +10 -8
  114. package/sdk/dist/generated/upgrader.d.ts +189 -18
  115. package/sdk/dist/generated/upgrader.js +84 -4
  116. package/sdk/dist/index.d.ts +1 -0
  117. package/sdk/dist/index.js +2 -0
  118. package/sdk/package.json +1 -1
  119. package/sdk/src/index.ts +3 -0
  120. package/sdk/test/oft-sml.test.ts +4 -4
  121. package/sdk/test/upgrader.test.ts +2 -3
  122. package/tools/ts-bindings-gen/src/main.rs +2 -1
  123. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
  124. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
  125. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
@@ -14,7 +14,8 @@ pub struct MockEndpoint;
14
14
  #[contractimpl]
15
15
  impl MockEndpoint {
16
16
  pub fn __constructor(env: Env, zro_token: &Address, native_token: &Address) {
17
- env.storage().instance().set(&symbol_short!("zro"), zro_token);
17
+ // Store as Option<Address> so zro() can return None when unavailable.
18
+ env.storage().instance().set(&symbol_short!("zro"), &Some(zro_token.clone()));
18
19
  env.storage().instance().set(&symbol_short!("ntk"), native_token);
19
20
  }
20
21
 
@@ -27,6 +28,11 @@ impl MockEndpoint {
27
28
  }
28
29
 
29
30
  pub fn send(env: Env, _sender: Address, params: MessagingParams, _refund_address: Address) -> MessagingReceipt {
31
+ // Record last send call for assertions
32
+ env.storage().instance().set(&symbol_short!("snds"), &_sender);
33
+ env.storage().instance().set(&symbol_short!("sndp"), &params);
34
+ env.storage().instance().set(&symbol_short!("sndr"), &_refund_address);
35
+
30
36
  // Return mock receipt
31
37
  MessagingReceipt {
32
38
  guid: BytesN::from_array(&env, &[1u8; 32]),
@@ -35,14 +41,26 @@ impl MockEndpoint {
35
41
  }
36
42
  }
37
43
 
44
+ pub fn last_send(env: Env) -> (Address, MessagingParams, Address) {
45
+ (
46
+ env.storage().instance().get(&symbol_short!("snds")).unwrap(),
47
+ env.storage().instance().get(&symbol_short!("sndp")).unwrap(),
48
+ env.storage().instance().get(&symbol_short!("sndr")).unwrap(),
49
+ )
50
+ }
51
+
38
52
  pub fn zro(env: Env) -> Option<Address> {
39
- // Return a mock ZRO token address
40
- env.storage().instance().get(&symbol_short!("zro")).unwrap()
53
+ // Return a mock ZRO token address (or None if not set)
54
+ env.storage().instance().get(&symbol_short!("zro")).unwrap_or(None)
41
55
  }
42
56
 
43
57
  pub fn native_token(env: Env) -> Address {
44
58
  env.storage().instance().get(&symbol_short!("ntk")).unwrap()
45
59
  }
60
+
61
+ pub fn set_zro(env: Env, zro: &Option<Address>) {
62
+ env.storage().instance().set(&symbol_short!("zro"), zro);
63
+ }
46
64
  }
47
65
 
48
66
  #[oapp_macros::oapp]
@@ -101,12 +119,12 @@ const UNSET_EID: u32 = 999;
101
119
 
102
120
  struct TestSetup<'a> {
103
121
  env: Env,
104
- #[allow(dead_code)]
105
122
  token_admin: Address,
106
123
  endpoint: Address,
107
- #[allow(dead_code)]
108
124
  owner: Address,
109
125
  oapp_client: DummyOAppSenderClient<'a>,
126
+ native_token: Address,
127
+ zro_token: Address,
110
128
  native_token_client: TokenClient<'a>,
111
129
  native_token_admin_client: StellarAssetClient<'a>,
112
130
  zro_token_admin_client: StellarAssetClient<'a>,
@@ -142,41 +160,124 @@ fn setup<'a>() -> TestSetup<'a> {
142
160
  native_token_client,
143
161
  native_token_admin_client,
144
162
  zro_token_admin_client,
163
+ native_token,
164
+ zro_token,
145
165
  owner,
146
166
  oapp_client,
147
167
  }
148
168
  }
149
169
 
150
- #[test]
151
- fn test_quote_with_peer_set() {
152
- let TestSetup { env, owner, oapp_client, .. } = setup();
153
-
154
- // Set peer for destination
155
- let peer = BytesN::from_array(&env, &[1; 32]);
170
+ fn set_peer_with_auth(
171
+ env: &Env,
172
+ owner: &Address,
173
+ oapp_client: &DummyOAppSenderClient<'_>,
174
+ eid: u32,
175
+ peer: &BytesN<32>,
176
+ ) {
156
177
  let peer_option = Some(peer.clone());
157
178
  env.mock_auths(&[MockAuth {
158
- address: &owner,
179
+ address: owner,
159
180
  invoke: &MockAuthInvoke {
160
181
  contract: &oapp_client.address,
161
182
  fn_name: "set_peer",
162
- args: (&REMOTE_EID, &peer_option).into_val(&env),
183
+ args: (&eid, &peer_option).into_val(env),
163
184
  sub_invokes: &[],
164
185
  },
165
186
  }]);
166
- oapp_client.set_peer(&REMOTE_EID, &peer_option);
187
+ oapp_client.set_peer(&eid, &peer_option);
188
+ }
189
+
190
+ fn mint_to(
191
+ env: &Env,
192
+ token_admin: &Address,
193
+ token: &Address,
194
+ token_admin_client: &StellarAssetClient<'_>,
195
+ to: &Address,
196
+ amount: i128,
197
+ ) {
198
+ env.mock_auths(&[MockAuth {
199
+ address: token_admin,
200
+ invoke: &MockAuthInvoke {
201
+ contract: token,
202
+ fn_name: "mint",
203
+ args: (to, amount).into_val(env),
204
+ sub_invokes: &[],
205
+ },
206
+ }]);
207
+ token_admin_client.mint(to, &amount);
208
+ }
209
+
210
+ fn mock_send_auth(
211
+ env: &Env,
212
+ sender: &Address,
213
+ oapp_client: &DummyOAppSenderClient<'_>,
214
+ dst_eid: u32,
215
+ message: &Bytes,
216
+ options: &Bytes,
217
+ fee: &MessagingFee,
218
+ refund_address: &Address,
219
+ native_token: &Address,
220
+ endpoint: &Address,
221
+ zro_token: &Address,
222
+ ) {
223
+ let native_transfer = MockAuthInvoke {
224
+ contract: native_token,
225
+ fn_name: "transfer",
226
+ args: (sender, endpoint, &fee.native_fee).into_val(env),
227
+ sub_invokes: &[],
228
+ };
229
+
230
+ if fee.zro_fee > 0 {
231
+ let zro_transfer = MockAuthInvoke {
232
+ contract: zro_token,
233
+ fn_name: "transfer",
234
+ args: (sender, endpoint, &fee.zro_fee).into_val(env),
235
+ sub_invokes: &[],
236
+ };
237
+ let sub_invokes = [native_transfer, zro_transfer];
238
+ env.mock_auths(&[MockAuth {
239
+ address: sender,
240
+ invoke: &MockAuthInvoke {
241
+ contract: &oapp_client.address,
242
+ fn_name: "send",
243
+ args: (sender, &dst_eid, message, options, fee, refund_address).into_val(env),
244
+ sub_invokes: &sub_invokes,
245
+ },
246
+ }]);
247
+ } else {
248
+ let sub_invokes = [native_transfer];
249
+ env.mock_auths(&[MockAuth {
250
+ address: sender,
251
+ invoke: &MockAuthInvoke {
252
+ contract: &oapp_client.address,
253
+ fn_name: "send",
254
+ args: (sender, &dst_eid, message, options, fee, refund_address).into_val(env),
255
+ sub_invokes: &sub_invokes,
256
+ },
257
+ }]);
258
+ }
259
+ }
260
+
261
+ #[test]
262
+ fn test_quote_with_peer_set() {
263
+ let TestSetup { env, owner, oapp_client, .. } = setup();
264
+
265
+ // Set peer for destination
266
+ let peer = BytesN::from_array(&env, &[1; 32]);
267
+ set_peer_with_auth(&env, &owner, &oapp_client, REMOTE_EID, &peer);
167
268
 
168
269
  let message = Bytes::from_array(&env, &[1, 2, 3, 4, 5]);
169
270
  let options = Bytes::from_array(&env, &[6, 7, 8]);
170
271
 
171
272
  // Test quote without ZRO
172
273
  let fee = oapp_client.quote(&REMOTE_EID, &message, &options, &false);
173
- assert!(fee.native_fee > 0);
274
+ assert_eq!(fee.native_fee, 1000);
174
275
  assert_eq!(fee.zro_fee, 0);
175
276
 
176
277
  // Test quote with ZRO
177
278
  let fee_with_zro = oapp_client.quote(&REMOTE_EID, &message, &options, &true);
178
- assert!(fee_with_zro.native_fee > 0);
179
- assert!(fee_with_zro.zro_fee > 0);
279
+ assert_eq!(fee_with_zro.native_fee, 1000);
280
+ assert_eq!(fee_with_zro.zro_fee, 500);
180
281
  }
181
282
 
182
283
  #[test]
@@ -193,80 +294,158 @@ fn test_quote_without_peer_panics() {
193
294
 
194
295
  #[test]
195
296
  fn test_lz_send_native_only() {
196
- let TestSetup { env, oapp_client, endpoint, native_token_client, native_token_admin_client, .. } = setup();
197
-
198
- env.mock_all_auths();
297
+ let TestSetup {
298
+ env,
299
+ oapp_client,
300
+ endpoint,
301
+ native_token,
302
+ zro_token,
303
+ native_token_client,
304
+ native_token_admin_client,
305
+ token_admin,
306
+ owner,
307
+ ..
308
+ } = setup();
199
309
 
200
310
  // Setup peer
201
311
  let peer = BytesN::from_array(&env, &[2; 32]);
202
- oapp_client.set_peer(&REMOTE_EID, &Some(peer));
312
+ set_peer_with_auth(&env, &owner, &oapp_client, REMOTE_EID, &peer);
203
313
 
204
- // Setup sender with funds
205
314
  let sender = Address::generate(&env);
206
- let initial_balance = 10000i128;
207
- native_token_admin_client.mint(&sender, &initial_balance);
315
+ mint_to(&env, &token_admin, &native_token, &native_token_admin_client, &sender, 1000i128);
208
316
 
209
317
  let message = Bytes::from_array(&env, &[1, 2, 3]);
210
318
  let options = Bytes::from_array(&env, &[]);
211
319
  let refund_address = Address::generate(&env);
212
-
213
320
  let fee = MessagingFee { native_fee: 1000, zro_fee: 0 };
214
321
 
215
- // Send message (auth is mocked automatically)
322
+ mock_send_auth(
323
+ &env,
324
+ &sender,
325
+ &oapp_client,
326
+ REMOTE_EID,
327
+ &message,
328
+ &options,
329
+ &fee,
330
+ &refund_address,
331
+ &native_token,
332
+ &endpoint,
333
+ &zro_token,
334
+ );
216
335
  let receipt = oapp_client.send(&sender, &REMOTE_EID, &message, &options, &fee, &refund_address);
217
336
 
218
- // Verify receipt
219
337
  assert_eq!(receipt.nonce, 1);
220
- assert_eq!(receipt.fee.native_fee, fee.native_fee);
221
-
222
- // Verify native token was transferred to endpoint
223
- let sender_balance = native_token_client.balance(&sender);
224
- assert_eq!(sender_balance, initial_balance - fee.native_fee);
225
-
226
- let endpoint_balance = native_token_client.balance(&endpoint);
227
- assert_eq!(endpoint_balance, fee.native_fee);
338
+ assert_eq!(receipt.fee.native_fee, 1000);
339
+ assert_eq!(receipt.fee.zro_fee, 0);
340
+
341
+ // Assert the endpoint received the correct send params
342
+ let endpoint_client = MockEndpointClient::new(&env, &endpoint);
343
+ let (endpoint_sender, params, refund) = endpoint_client.last_send();
344
+ assert_eq!(endpoint_sender, oapp_client.address);
345
+ assert_eq!(params.dst_eid, REMOTE_EID);
346
+ assert_eq!(params.receiver, peer);
347
+ assert_eq!(params.message, message);
348
+ assert_eq!(params.options, options);
349
+ assert_eq!(params.pay_in_zro, false);
350
+ assert_eq!(refund, refund_address);
351
+
352
+ assert_eq!(native_token_client.balance(&sender), 0);
353
+ assert_eq!(native_token_client.balance(&endpoint), 1000);
354
+ assert_eq!(TokenClient::new(&env, &zro_token).balance(&endpoint), 0);
228
355
  }
229
356
 
230
357
  #[test]
231
358
  fn test_lz_send_with_zro() {
232
- let TestSetup { env, oapp_client, native_token_admin_client, zro_token_admin_client, .. } = setup();
233
-
234
- env.mock_all_auths();
359
+ let TestSetup {
360
+ env,
361
+ oapp_client,
362
+ endpoint,
363
+ native_token,
364
+ zro_token,
365
+ native_token_client,
366
+ native_token_admin_client,
367
+ zro_token_admin_client,
368
+ token_admin,
369
+ owner,
370
+ ..
371
+ } = setup();
235
372
 
236
373
  // Setup peer
237
374
  let peer = BytesN::from_array(&env, &[3; 32]);
238
- oapp_client.set_peer(&REMOTE_EID, &Some(peer));
239
-
240
- // Setup sender with both native and ZRO funds
241
- let fee = MessagingFee { native_fee: 1000, zro_fee: 500 };
375
+ set_peer_with_auth(&env, &owner, &oapp_client, REMOTE_EID, &peer);
242
376
 
243
377
  let sender = Address::generate(&env);
244
- native_token_admin_client.mint(&sender, &fee.native_fee);
245
- zro_token_admin_client.mint(&sender, &fee.zro_fee);
378
+ let fee = MessagingFee { native_fee: 1000, zro_fee: 500 };
379
+ mint_to(&env, &token_admin, &native_token, &native_token_admin_client, &sender, fee.native_fee);
380
+ mint_to(&env, &token_admin, &zro_token, &zro_token_admin_client, &sender, fee.zro_fee);
246
381
 
247
- let message = Bytes::from_array(&env, &[1, 2, 3, 4]);
248
- let options = Bytes::from_array(&env, &[5]);
382
+ let message = Bytes::from_array(&env, &[4, 5, 6]);
383
+ let options = Bytes::from_array(&env, &[7]);
249
384
  let refund_address = Address::generate(&env);
250
385
 
251
- // Send message with ZRO payment
386
+ mock_send_auth(
387
+ &env,
388
+ &sender,
389
+ &oapp_client,
390
+ REMOTE_EID,
391
+ &message,
392
+ &options,
393
+ &fee,
394
+ &refund_address,
395
+ &native_token,
396
+ &endpoint,
397
+ &zro_token,
398
+ );
252
399
  let receipt = oapp_client.send(&sender, &REMOTE_EID, &message, &options, &fee, &refund_address);
253
400
 
254
- assert_eq!(receipt.fee.zro_fee, fee.zro_fee);
401
+ assert_eq!(receipt.nonce, 1);
402
+ assert_eq!(receipt.fee.native_fee, 1000);
403
+ assert_eq!(receipt.fee.zro_fee, 500);
404
+
405
+ // Assert the endpoint received the correct send params
406
+ let endpoint_client = MockEndpointClient::new(&env, &endpoint);
407
+ let (endpoint_sender, params, refund) = endpoint_client.last_send();
408
+ assert_eq!(endpoint_sender, oapp_client.address);
409
+ assert_eq!(params.dst_eid, REMOTE_EID);
410
+ assert_eq!(params.receiver, peer);
411
+ assert_eq!(params.message, message);
412
+ assert_eq!(params.options, options);
413
+ assert_eq!(params.pay_in_zro, true);
414
+ assert_eq!(refund, refund_address);
415
+
416
+ assert_eq!(native_token_client.balance(&sender), 0);
417
+ assert_eq!(native_token_client.balance(&endpoint), 1000);
418
+
419
+ let zro_token_client = TokenClient::new(&env, &zro_token);
420
+ assert_eq!(zro_token_client.balance(&sender), 0);
421
+ assert_eq!(zro_token_client.balance(&endpoint), 500);
255
422
  }
256
423
 
257
424
  #[test]
258
425
  fn test_pay_native() {
259
- let TestSetup { env, oapp_client, endpoint, native_token_admin_client, .. } = setup();
260
-
261
- env.mock_all_auths();
426
+ let TestSetup { env, oapp_client, endpoint, native_token, native_token_admin_client, token_admin, .. } = setup();
262
427
 
263
428
  let payer = Address::generate(&env);
264
429
  let payment_amount = 2000i128;
265
430
 
266
431
  // Fund the payer
267
- native_token_admin_client.mint(&payer, &payment_amount);
432
+ mint_to(&env, &token_admin, &native_token, &native_token_admin_client, &payer, payment_amount);
268
433
 
269
434
  // Make payment
435
+ env.mock_auths(&[MockAuth {
436
+ address: &payer,
437
+ invoke: &MockAuthInvoke {
438
+ contract: &oapp_client.address,
439
+ fn_name: "pay_native_fee",
440
+ args: (&payer, &payment_amount).into_val(&env),
441
+ sub_invokes: &[MockAuthInvoke {
442
+ contract: &native_token,
443
+ fn_name: "transfer",
444
+ args: (&payer, &endpoint, &payment_amount).into_val(&env),
445
+ sub_invokes: &[],
446
+ }],
447
+ },
448
+ }]);
270
449
  oapp_client.pay_native_fee(&payer, &payment_amount);
271
450
 
272
451
  // Verify balances
@@ -277,9 +456,7 @@ fn test_pay_native() {
277
456
  #[test]
278
457
  #[should_panic(expected = "balance is not sufficient to spend")]
279
458
  fn test_pay_native_insufficient_balance() {
280
- let TestSetup { env, oapp_client, native_token_admin_client, .. } = setup();
281
-
282
- env.mock_all_auths();
459
+ let TestSetup { env, oapp_client, endpoint, native_token, native_token_admin_client, token_admin, .. } = setup();
283
460
 
284
461
  let balance = 500i128;
285
462
  let payment_amount = 1000i128;
@@ -287,8 +464,106 @@ fn test_pay_native_insufficient_balance() {
287
464
  let payer = Address::generate(&env);
288
465
 
289
466
  // Fund with less than required
290
- native_token_admin_client.mint(&payer, &balance);
467
+ mint_to(&env, &token_admin, &native_token, &native_token_admin_client, &payer, balance);
291
468
 
292
469
  // This should panic due to insufficient balance
470
+ env.mock_auths(&[MockAuth {
471
+ address: &payer,
472
+ invoke: &MockAuthInvoke {
473
+ contract: &oapp_client.address,
474
+ fn_name: "pay_native_fee",
475
+ args: (&payer, &payment_amount).into_val(&env),
476
+ sub_invokes: &[MockAuthInvoke {
477
+ contract: &native_token,
478
+ fn_name: "transfer",
479
+ args: (&payer, &endpoint, &payment_amount).into_val(&env),
480
+ sub_invokes: &[],
481
+ }],
482
+ },
483
+ }]);
293
484
  oapp_client.pay_native_fee(&payer, &payment_amount);
294
485
  }
486
+
487
+ #[test]
488
+ fn test_pay_zro_success() {
489
+ let TestSetup { env, oapp_client, endpoint, zro_token, zro_token_admin_client, token_admin, .. } = setup();
490
+
491
+ let payer = Address::generate(&env);
492
+ let payment_amount = 500i128;
493
+ mint_to(&env, &token_admin, &zro_token, &zro_token_admin_client, &payer, payment_amount);
494
+
495
+ env.mock_auths(&[MockAuth {
496
+ address: &payer,
497
+ invoke: &MockAuthInvoke {
498
+ contract: &oapp_client.address,
499
+ fn_name: "pay_zro_fee",
500
+ args: (&payer, &payment_amount).into_val(&env),
501
+ sub_invokes: &[MockAuthInvoke {
502
+ contract: &zro_token,
503
+ fn_name: "transfer",
504
+ args: (&payer, &endpoint, &payment_amount).into_val(&env),
505
+ sub_invokes: &[],
506
+ }],
507
+ },
508
+ }]);
509
+ oapp_client.pay_zro_fee(&payer, &payment_amount);
510
+
511
+ assert_eq!(zro_token_admin_client.balance(&payer), 0);
512
+ assert_eq!(zro_token_admin_client.balance(&endpoint), payment_amount);
513
+ }
514
+
515
+ #[test]
516
+ #[should_panic(expected = "balance is not sufficient to spend")]
517
+ fn test_pay_zro_insufficient_balance() {
518
+ let TestSetup { env, oapp_client, endpoint, zro_token, zro_token_admin_client, token_admin, .. } = setup();
519
+
520
+ let payer = Address::generate(&env);
521
+ let balance = 100i128;
522
+ let payment_amount = 500i128;
523
+
524
+ // Fund with less than required
525
+ mint_to(&env, &token_admin, &zro_token, &zro_token_admin_client, &payer, balance);
526
+
527
+ env.mock_auths(&[MockAuth {
528
+ address: &payer,
529
+ invoke: &MockAuthInvoke {
530
+ contract: &oapp_client.address,
531
+ fn_name: "pay_zro_fee",
532
+ args: (&payer, &payment_amount).into_val(&env),
533
+ sub_invokes: &[MockAuthInvoke {
534
+ contract: &zro_token,
535
+ fn_name: "transfer",
536
+ args: (&payer, &endpoint, &payment_amount).into_val(&env),
537
+ sub_invokes: &[],
538
+ }],
539
+ },
540
+ }]);
541
+ oapp_client.pay_zro_fee(&payer, &payment_amount);
542
+ }
543
+
544
+ #[test]
545
+ fn test_pay_zro_unavailable_returns_error() {
546
+ let TestSetup { env, oapp_client, endpoint, zro_token, .. } = setup();
547
+
548
+ let endpoint_client = MockEndpointClient::new(&env, &endpoint);
549
+ endpoint_client.set_zro(&None);
550
+
551
+ let payer = Address::generate(&env);
552
+ let payment_amount = 500i128;
553
+
554
+ env.mock_auths(&[MockAuth {
555
+ address: &payer,
556
+ invoke: &MockAuthInvoke {
557
+ contract: &oapp_client.address,
558
+ fn_name: "pay_zro_fee",
559
+ args: (&payer, &payment_amount).into_val(&env),
560
+ sub_invokes: &[],
561
+ },
562
+ }]);
563
+ let result = oapp_client.try_pay_zro_fee(&payer, &payment_amount);
564
+ assert_eq!(result.err().unwrap().ok().unwrap(), OAppError::ZroTokenUnavailable.into());
565
+
566
+ // Ensure we did not transfer any ZRO accidentally
567
+ let token_client = TokenClient::new(&env, &zro_token);
568
+ assert_eq!(token_client.balance(&payer), 0);
569
+ }
@@ -6,6 +6,10 @@ use utils::{option_ext::OptionExt, ownable::Ownable};
6
6
  /// Used as denominator in fee calculations
7
7
  const BASE_FEE_BPS: u64 = 10_000;
8
8
 
9
+ // =========================================================================
10
+ // Storage
11
+ // =========================================================================
12
+
9
13
  #[storage]
10
14
  pub enum OFTFeeStorage {
11
15
  #[instance(u64)]
@@ -19,14 +23,22 @@ pub enum OFTFeeStorage {
19
23
  FeeDepositAddress,
20
24
  }
21
25
 
26
+ // =========================================================================
27
+ // Errors
28
+ // =========================================================================
29
+
22
30
  #[contract_error]
23
31
  pub enum OFTFeeError {
24
- InvalidFeeBps = 2200,
32
+ InvalidFeeBps = 3100,
25
33
  InvalidFeeDepositAddress,
26
34
  NotFound,
27
35
  SameValue,
28
36
  }
29
37
 
38
+ // =========================================================================
39
+ // Events
40
+ // =========================================================================
41
+
30
42
  #[contractevent]
31
43
  #[derive(Clone, Debug, Eq, PartialEq)]
32
44
  pub struct DefaultFeeBpsSet {
@@ -52,8 +64,12 @@ pub struct FeeDepositAddressSet {
52
64
  pub fee_deposit_address: Address,
53
65
  }
54
66
 
67
+ // =========================================================================
68
+ // Trait With Default Implementations
69
+ // =========================================================================
70
+
55
71
  #[contract_trait]
56
- pub trait OFTFee: OFTFeeInternal + Ownable + Sized {
72
+ pub trait OFTFee: OFTFeeInternal + Ownable {
57
73
  #[only_auth]
58
74
  fn set_default_fee_bps(env: &Env, default_fee_bps: u64) {
59
75
  assert_with_error!(env, default_fee_bps <= BASE_FEE_BPS, OFTFeeError::InvalidFeeBps);
@@ -2,6 +2,10 @@ use common_macros::{contract_error, contract_trait, only_auth, storage};
2
2
  use soroban_sdk::{assert_with_error, contractevent, Env};
3
3
  use utils::ownable::Ownable;
4
4
 
5
+ // =========================================================================
6
+ // Storage
7
+ // =========================================================================
8
+
5
9
  #[storage]
6
10
  pub enum OFTPausableStorage {
7
11
  #[instance(bool)]
@@ -9,24 +13,35 @@ pub enum OFTPausableStorage {
9
13
  Paused,
10
14
  }
11
15
 
16
+ // =========================================================================
17
+ // Errors
18
+ // =========================================================================
19
+
12
20
  #[contract_error]
13
21
  pub enum OFTPausableError {
14
- Paused = 2300,
22
+ Paused = 3110,
15
23
  PauseStatusUnchanged,
16
24
  }
17
25
 
26
+ // =========================================================================
27
+ // Events
28
+ // =========================================================================
29
+
18
30
  #[contractevent]
19
31
  #[derive(Clone, Debug, Eq, PartialEq)]
20
32
  pub struct PausedSet {
21
33
  pub paused: bool,
22
34
  }
23
35
 
36
+ // =========================================================================
37
+ // Trait With Default Implementations
38
+ // =========================================================================
39
+
24
40
  #[contract_trait]
25
- pub trait OFTPausable: OFTPausableInternal + Ownable + Sized {
41
+ pub trait OFTPausable: OFTPausableInternal + Ownable {
26
42
  #[only_auth]
27
43
  fn set_paused(env: &Env, paused: bool) {
28
- let current_paused = OFTPausableStorage::paused(env);
29
- assert_with_error!(env, current_paused != paused, OFTPausableError::PauseStatusUnchanged);
44
+ assert_with_error!(env, Self::is_paused(env) != paused, OFTPausableError::PauseStatusUnchanged);
30
45
  OFTPausableStorage::set_paused(env, &paused);
31
46
  PausedSet { paused }.publish(env);
32
47
  }