@layerzerolabs/protocol-stellar-v2 0.2.40 → 0.2.41

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 (114) hide show
  1. package/.turbo/turbo-build.log +226 -313
  2. package/.turbo/turbo-lint.log +98 -227
  3. package/.turbo/turbo-test.log +1803 -1954
  4. package/contracts/common-macros/src/lib.rs +38 -15
  5. package/contracts/common-macros/src/lz_contract.rs +12 -21
  6. package/contracts/common-macros/src/tests/lz_contract.rs +17 -8
  7. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__lz_contract__snapshot_generated_lz_contract_code.snap +20 -0
  8. package/contracts/common-macros/src/upgradeable.rs +37 -30
  9. package/contracts/endpoint-v2/src/endpoint_v2.rs +4 -3
  10. package/contracts/endpoint-v2/src/errors.rs +2 -2
  11. package/contracts/endpoint-v2/src/messaging_channel.rs +11 -0
  12. package/contracts/endpoint-v2/src/messaging_composer.rs +1 -0
  13. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +12 -25
  14. package/contracts/endpoint-v2/src/tests/endpoint_v2/initializable.rs +4 -4
  15. package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +50 -10
  16. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +6 -35
  17. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +2 -2
  18. package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +50 -1
  19. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +78 -0
  20. package/contracts/endpoint-v2/src/tests/messaging_channel/insert_and_drain_pending_nonces.rs +272 -0
  21. package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -0
  22. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +10 -5
  23. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +30 -0
  24. package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +22 -1
  25. package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +13 -11
  26. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +13 -10
  27. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +15 -11
  28. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +3 -2
  29. package/contracts/macro-integration-tests/tests/runtime/ownable/two_step_transfer.rs +14 -12
  30. package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +3 -9
  31. package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_invalid_inner_option.stderr +24 -1
  32. package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_missing_internal.stderr +3 -3
  33. package/contracts/macro-integration-tests/tests/ui/lz_contract/pass/upgradeable_rbac.rs +44 -0
  34. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +3 -0
  35. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +3 -0
  36. package/contracts/macro-integration-tests/tests/ui/ownable/pass/basic.rs +1 -1
  37. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/attr_args.stderr +1 -1
  38. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_auth_trait.stderr +2 -2
  39. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_upgradeable_internal.stderr +2 -2
  40. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/rbac.rs +44 -0
  41. package/contracts/oapps/counter/integration_tests/utils.rs +5 -3
  42. package/contracts/oapps/counter/src/tests/mod.rs +16 -1
  43. package/contracts/oapps/counter/src/tests/test_counter.rs +5 -2
  44. package/contracts/oapps/oapp/src/oapp_core.rs +21 -7
  45. package/contracts/oapps/oapp/src/oapp_options_type3.rs +7 -5
  46. package/contracts/oapps/oapp/src/tests/mod.rs +21 -0
  47. package/contracts/oapps/oapp/src/tests/oapp_core.rs +12 -10
  48. package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +11 -7
  49. package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +4 -2
  50. package/contracts/oapps/oapp/src/tests/oapp_sender.rs +3 -2
  51. package/contracts/oapps/oapp/src/tests/test_macros.rs +15 -0
  52. package/contracts/oapps/oapp-macros/src/generators.rs +6 -0
  53. package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +15 -0
  54. package/contracts/oapps/oft/integration-tests/setup.rs +22 -4
  55. package/contracts/oapps/oft/integration-tests/utils.rs +94 -13
  56. package/contracts/oapps/oft/src/extensions/oft_fee.rs +23 -10
  57. package/contracts/oapps/oft/src/extensions/pausable.rs +31 -10
  58. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +9 -4
  59. package/contracts/oapps/oft/src/oft.rs +1 -2
  60. package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +39 -27
  61. package/contracts/oapps/oft/src/tests/extensions/pausable.rs +38 -24
  62. package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +87 -69
  63. package/contracts/oapps/oft-core/integration-tests/setup.rs +27 -3
  64. package/contracts/oapps/oft-core/src/oft_core.rs +10 -5
  65. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +20 -20
  66. package/contracts/oapps/oft-core/src/tests/test_utils.rs +31 -3
  67. package/contracts/upgrader/src/lib.rs +67 -30
  68. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract3.wasm +0 -0
  69. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract4.wasm +0 -0
  70. package/contracts/upgrader/src/tests/test_upgrader.rs +50 -4
  71. package/contracts/utils/src/ownable.rs +16 -5
  72. package/contracts/utils/src/tests/ownable.rs +39 -39
  73. package/contracts/utils/src/upgradeable.rs +60 -17
  74. package/docs/oapp-guide.md +4 -4
  75. package/package.json +3 -4
  76. package/sdk/.turbo/turbo-test.log +381 -366
  77. package/sdk/dist/generated/bml.d.ts +4 -4
  78. package/sdk/dist/generated/bml.js +6 -6
  79. package/sdk/dist/generated/counter.d.ts +158 -12
  80. package/sdk/dist/generated/counter.js +32 -12
  81. package/sdk/dist/generated/dvn.d.ts +4 -6
  82. package/sdk/dist/generated/dvn.js +8 -8
  83. package/sdk/dist/generated/dvn_fee_lib.d.ts +8 -10
  84. package/sdk/dist/generated/dvn_fee_lib.js +8 -8
  85. package/sdk/dist/generated/endpoint.d.ts +9 -9
  86. package/sdk/dist/generated/endpoint.js +9 -9
  87. package/sdk/dist/generated/executor.d.ts +9 -11
  88. package/sdk/dist/generated/executor.js +11 -11
  89. package/sdk/dist/generated/executor_fee_lib.d.ts +9 -11
  90. package/sdk/dist/generated/executor_fee_lib.js +11 -11
  91. package/sdk/dist/generated/executor_helper.d.ts +4 -4
  92. package/sdk/dist/generated/executor_helper.js +6 -6
  93. package/sdk/dist/generated/layerzero_view.d.ts +9 -11
  94. package/sdk/dist/generated/layerzero_view.js +11 -11
  95. package/sdk/dist/generated/oft.d.ts +194 -27
  96. package/sdk/dist/generated/oft.js +44 -22
  97. package/sdk/dist/generated/price_feed.d.ts +8 -10
  98. package/sdk/dist/generated/price_feed.js +8 -8
  99. package/sdk/dist/generated/sac_manager.d.ts +8 -8
  100. package/sdk/dist/generated/sac_manager.js +6 -6
  101. package/sdk/dist/generated/sml.d.ts +9 -9
  102. package/sdk/dist/generated/sml.js +9 -9
  103. package/sdk/dist/generated/treasury.d.ts +9 -9
  104. package/sdk/dist/generated/treasury.js +9 -9
  105. package/sdk/dist/generated/uln302.d.ts +9 -9
  106. package/sdk/dist/generated/uln302.js +9 -9
  107. package/sdk/dist/generated/upgrader.d.ts +25 -16
  108. package/sdk/dist/generated/upgrader.js +5 -5
  109. package/sdk/package.json +1 -1
  110. package/sdk/test/counter-sml.test.ts +20 -0
  111. package/sdk/test/counter-uln.test.ts +20 -0
  112. package/sdk/test/oft-sml.test.ts +22 -0
  113. package/sdk/test/upgrader.test.ts +1 -0
  114. package/turbo.json +1 -8
@@ -169,11 +169,11 @@ fn transfer_ownership_blocked_during_2step() {
169
169
  invoke: &MockAuthInvoke {
170
170
  contract: &contract,
171
171
  args: (&new_owner, ttl).into_val(&env),
172
- fn_name: "propose_ownership_transfer",
172
+ fn_name: "begin_ownership_transfer",
173
173
  sub_invokes: &[],
174
174
  },
175
175
  }]);
176
- client.propose_ownership_transfer(&new_owner, &ttl);
176
+ client.begin_ownership_transfer(&new_owner, &ttl);
177
177
 
178
178
  // Try single-step transfer - should fail
179
179
  env.mock_auths(&[MockAuth {
@@ -193,7 +193,7 @@ fn transfer_ownership_blocked_during_2step() {
193
193
  // ============================================
194
194
 
195
195
  #[test]
196
- fn propose_ownership_transfer_initiate_and_accept() {
196
+ fn begin_ownership_transfer_initiate_and_accept() {
197
197
  let env = Env::default();
198
198
  let owner = Address::generate(&env);
199
199
  let new_owner = Address::generate(&env);
@@ -212,11 +212,11 @@ fn propose_ownership_transfer_initiate_and_accept() {
212
212
  invoke: &MockAuthInvoke {
213
213
  contract: &contract,
214
214
  args: (&new_owner, ttl).into_val(&env),
215
- fn_name: "propose_ownership_transfer",
215
+ fn_name: "begin_ownership_transfer",
216
216
  sub_invokes: &[],
217
217
  },
218
218
  }]);
219
- client.propose_ownership_transfer(&new_owner, &ttl);
219
+ client.begin_ownership_transfer(&new_owner, &ttl);
220
220
 
221
221
  assert_eq_event(
222
222
  &env,
@@ -262,11 +262,11 @@ fn pending_owner_expires_after_ttl() {
262
262
  invoke: &MockAuthInvoke {
263
263
  contract: &contract,
264
264
  args: (&new_owner, ttl).into_val(&env),
265
- fn_name: "propose_ownership_transfer",
265
+ fn_name: "begin_ownership_transfer",
266
266
  sub_invokes: &[],
267
267
  },
268
268
  }]);
269
- client.propose_ownership_transfer(&new_owner, &ttl);
269
+ client.begin_ownership_transfer(&new_owner, &ttl);
270
270
  assert_eq!(client.pending_owner(), Some(new_owner.clone()));
271
271
 
272
272
  // Advance ledger beyond the actual storage TTL window; temporary pending owner entry should expire.
@@ -287,7 +287,7 @@ fn pending_owner_expires_after_ttl() {
287
287
  }
288
288
 
289
289
  #[test]
290
- fn propose_ownership_transfer_cancel() {
290
+ fn begin_ownership_transfer_cancel() {
291
291
  let env = Env::default();
292
292
  let owner = Address::generate(&env);
293
293
  let new_owner = Address::generate(&env);
@@ -303,11 +303,11 @@ fn propose_ownership_transfer_cancel() {
303
303
  invoke: &MockAuthInvoke {
304
304
  contract: &contract,
305
305
  args: (&new_owner, ttl).into_val(&env),
306
- fn_name: "propose_ownership_transfer",
306
+ fn_name: "begin_ownership_transfer",
307
307
  sub_invokes: &[],
308
308
  },
309
309
  }]);
310
- client.propose_ownership_transfer(&new_owner, &ttl);
310
+ client.begin_ownership_transfer(&new_owner, &ttl);
311
311
 
312
312
  assert_eq!(client.pending_owner(), Some(new_owner.clone()));
313
313
 
@@ -317,11 +317,11 @@ fn propose_ownership_transfer_cancel() {
317
317
  invoke: &MockAuthInvoke {
318
318
  contract: &contract,
319
319
  args: (&new_owner, 0u32).into_val(&env),
320
- fn_name: "propose_ownership_transfer",
320
+ fn_name: "begin_ownership_transfer",
321
321
  sub_invokes: &[],
322
322
  },
323
323
  }]);
324
- client.propose_ownership_transfer(&new_owner, &0u32);
324
+ client.begin_ownership_transfer(&new_owner, &0u32);
325
325
 
326
326
  // No event emitted on cancel (matching OpenZeppelin behavior)
327
327
  assert_eq!(client.owner(), Some(owner)); // Still old owner
@@ -329,7 +329,7 @@ fn propose_ownership_transfer_cancel() {
329
329
  }
330
330
 
331
331
  #[test]
332
- fn propose_ownership_transfer_with_max_ttl() {
332
+ fn begin_ownership_transfer_with_max_ttl() {
333
333
  let env = Env::default();
334
334
  let owner = Address::generate(&env);
335
335
  let new_owner = Address::generate(&env);
@@ -345,11 +345,11 @@ fn propose_ownership_transfer_with_max_ttl() {
345
345
  invoke: &MockAuthInvoke {
346
346
  contract: &contract,
347
347
  args: (&new_owner, max_ttl).into_val(&env),
348
- fn_name: "propose_ownership_transfer",
348
+ fn_name: "begin_ownership_transfer",
349
349
  sub_invokes: &[],
350
350
  },
351
351
  }]);
352
- client.propose_ownership_transfer(&new_owner, &max_ttl);
352
+ client.begin_ownership_transfer(&new_owner, &max_ttl);
353
353
 
354
354
  assert_eq!(client.pending_owner(), Some(new_owner.clone()));
355
355
 
@@ -363,7 +363,7 @@ fn propose_ownership_transfer_with_max_ttl() {
363
363
 
364
364
  #[test]
365
365
  #[should_panic(expected = "Error(Contract, #1033)")] // NoPendingTransfer
366
- fn propose_ownership_transfer_cancel_no_pending_fails() {
366
+ fn begin_ownership_transfer_cancel_no_pending_fails() {
367
367
  let env = Env::default();
368
368
  let owner = Address::generate(&env);
369
369
  let new_owner = Address::generate(&env);
@@ -377,16 +377,16 @@ fn propose_ownership_transfer_cancel_no_pending_fails() {
377
377
  invoke: &MockAuthInvoke {
378
378
  contract: &contract,
379
379
  args: (&new_owner, 0u32).into_val(&env),
380
- fn_name: "propose_ownership_transfer",
380
+ fn_name: "begin_ownership_transfer",
381
381
  sub_invokes: &[],
382
382
  },
383
383
  }]);
384
- client.propose_ownership_transfer(&new_owner, &0u32);
384
+ client.begin_ownership_transfer(&new_owner, &0u32);
385
385
  }
386
386
 
387
387
  #[test]
388
388
  #[should_panic(expected = "Error(Contract, #1031)")] // InvalidPendingOwner
389
- fn propose_ownership_transfer_cancel_wrong_address_fails() {
389
+ fn begin_ownership_transfer_cancel_wrong_address_fails() {
390
390
  let env = Env::default();
391
391
  let owner = Address::generate(&env);
392
392
  let new_owner = Address::generate(&env);
@@ -403,11 +403,11 @@ fn propose_ownership_transfer_cancel_wrong_address_fails() {
403
403
  invoke: &MockAuthInvoke {
404
404
  contract: &contract,
405
405
  args: (&new_owner, ttl).into_val(&env),
406
- fn_name: "propose_ownership_transfer",
406
+ fn_name: "begin_ownership_transfer",
407
407
  sub_invokes: &[],
408
408
  },
409
409
  }]);
410
- client.propose_ownership_transfer(&new_owner, &ttl);
410
+ client.begin_ownership_transfer(&new_owner, &ttl);
411
411
 
412
412
  // Try to cancel with wrong address
413
413
  env.mock_auths(&[MockAuth {
@@ -415,16 +415,16 @@ fn propose_ownership_transfer_cancel_wrong_address_fails() {
415
415
  invoke: &MockAuthInvoke {
416
416
  contract: &contract,
417
417
  args: (&wrong_owner, 0u32).into_val(&env),
418
- fn_name: "propose_ownership_transfer",
418
+ fn_name: "begin_ownership_transfer",
419
419
  sub_invokes: &[],
420
420
  },
421
421
  }]);
422
- client.propose_ownership_transfer(&wrong_owner, &0u32);
422
+ client.begin_ownership_transfer(&wrong_owner, &0u32);
423
423
  }
424
424
 
425
425
  #[test]
426
426
  #[should_panic(expected = "Error(Contract, #1032)")] // InvalidTtl
427
- fn propose_ownership_transfer_invalid_ttl_exceeds_max_fails() {
427
+ fn begin_ownership_transfer_invalid_ttl_exceeds_max_fails() {
428
428
  let env = Env::default();
429
429
  let owner = Address::generate(&env);
430
430
  let new_owner = Address::generate(&env);
@@ -440,12 +440,12 @@ fn propose_ownership_transfer_invalid_ttl_exceeds_max_fails() {
440
440
  invoke: &MockAuthInvoke {
441
441
  contract: &contract,
442
442
  args: (&new_owner, ttl).into_val(&env),
443
- fn_name: "propose_ownership_transfer",
443
+ fn_name: "begin_ownership_transfer",
444
444
  sub_invokes: &[],
445
445
  },
446
446
  }]);
447
447
 
448
- client.propose_ownership_transfer(&new_owner, &ttl);
448
+ client.begin_ownership_transfer(&new_owner, &ttl);
449
449
  }
450
450
 
451
451
  #[test]
@@ -490,11 +490,11 @@ fn accept_ownership_wrong_address_fails() {
490
490
  invoke: &MockAuthInvoke {
491
491
  contract: &contract,
492
492
  args: (&new_owner, ttl).into_val(&env),
493
- fn_name: "propose_ownership_transfer",
493
+ fn_name: "begin_ownership_transfer",
494
494
  sub_invokes: &[],
495
495
  },
496
496
  }]);
497
- client.propose_ownership_transfer(&new_owner, &ttl);
497
+ client.begin_ownership_transfer(&new_owner, &ttl);
498
498
 
499
499
  // Try to accept with wrong address
500
500
  env.mock_auths(&[MockAuth {
@@ -510,7 +510,7 @@ fn accept_ownership_wrong_address_fails() {
510
510
  }
511
511
 
512
512
  #[test]
513
- fn propose_ownership_transfer_override_pending() {
513
+ fn begin_ownership_transfer_override_pending() {
514
514
  let env = Env::default();
515
515
  let owner = Address::generate(&env);
516
516
  let new_owner1 = Address::generate(&env);
@@ -527,11 +527,11 @@ fn propose_ownership_transfer_override_pending() {
527
527
  invoke: &MockAuthInvoke {
528
528
  contract: &contract,
529
529
  args: (&new_owner1, ttl).into_val(&env),
530
- fn_name: "propose_ownership_transfer",
530
+ fn_name: "begin_ownership_transfer",
531
531
  sub_invokes: &[],
532
532
  },
533
533
  }]);
534
- client.propose_ownership_transfer(&new_owner1, &ttl);
534
+ client.begin_ownership_transfer(&new_owner1, &ttl);
535
535
 
536
536
  assert_eq!(client.pending_owner(), Some(new_owner1.clone()));
537
537
 
@@ -541,11 +541,11 @@ fn propose_ownership_transfer_override_pending() {
541
541
  invoke: &MockAuthInvoke {
542
542
  contract: &contract,
543
543
  args: (&new_owner2, ttl).into_val(&env),
544
- fn_name: "propose_ownership_transfer",
544
+ fn_name: "begin_ownership_transfer",
545
545
  sub_invokes: &[],
546
546
  },
547
547
  }]);
548
- client.propose_ownership_transfer(&new_owner2, &ttl);
548
+ client.begin_ownership_transfer(&new_owner2, &ttl);
549
549
 
550
550
  assert_eq!(client.pending_owner(), Some(new_owner2.clone()));
551
551
 
@@ -636,11 +636,11 @@ fn renounce_blocked_during_2step_transfer() {
636
636
  invoke: &MockAuthInvoke {
637
637
  contract: &contract,
638
638
  args: (&new_owner, ttl).into_val(&env),
639
- fn_name: "propose_ownership_transfer",
639
+ fn_name: "begin_ownership_transfer",
640
640
  sub_invokes: &[],
641
641
  },
642
642
  }]);
643
- client.propose_ownership_transfer(&new_owner, &ttl);
643
+ client.begin_ownership_transfer(&new_owner, &ttl);
644
644
 
645
645
  // Try to renounce - should fail
646
646
  env.mock_auths(&[MockAuth {
@@ -703,11 +703,11 @@ fn chain_new_owner_can_transfer_2step() {
703
703
  invoke: &MockAuthInvoke {
704
704
  contract: &contract,
705
705
  args: (&new_owner, ttl).into_val(&env),
706
- fn_name: "propose_ownership_transfer",
706
+ fn_name: "begin_ownership_transfer",
707
707
  sub_invokes: &[],
708
708
  },
709
709
  }]);
710
- client.propose_ownership_transfer(&new_owner, &ttl);
710
+ client.begin_ownership_transfer(&new_owner, &ttl);
711
711
 
712
712
  env.mock_auths(&[MockAuth {
713
713
  address: &new_owner,
@@ -726,11 +726,11 @@ fn chain_new_owner_can_transfer_2step() {
726
726
  invoke: &MockAuthInvoke {
727
727
  contract: &contract,
728
728
  args: (&third_owner, ttl).into_val(&env),
729
- fn_name: "propose_ownership_transfer",
729
+ fn_name: "begin_ownership_transfer",
730
730
  sub_invokes: &[],
731
731
  },
732
732
  }]);
733
- client.propose_ownership_transfer(&third_owner, &ttl);
733
+ client.begin_ownership_transfer(&third_owner, &ttl);
734
734
 
735
735
  env.mock_auths(&[MockAuth {
736
736
  address: &third_owner,
@@ -1,8 +1,11 @@
1
- use crate::{self as utils, auth::Auth, errors::UpgradeableError, option_ext::OptionExt};
2
- use common_macros::{contract_trait, only_auth, storage};
3
- use soroban_sdk::{assert_with_error, xdr::FromXdr, Env};
1
+ use crate::{self as utils, auth::Auth, errors::UpgradeableError, option_ext::OptionExt, rbac::RoleBasedAccessControl};
2
+ use common_macros::{contract_trait, only_auth, only_role, storage};
3
+ use soroban_sdk::{assert_with_error, xdr::FromXdr, Bytes, BytesN, Env};
4
4
 
5
- /// Trait for contracts with upgrade and migration support.
5
+ /// Role for upgrading the contract and running migrations.
6
+ pub const UPGRADER_ROLE: &str = "UPGRADER_ROLE";
7
+
8
+ /// Trait for contracts with upgrade and migration support (Auth-based).
6
9
  ///
7
10
  /// Implements a two-phase upgrade pattern:
8
11
  /// 1. `upgrade` - Updates WASM bytecode and sets migration flag
@@ -12,32 +15,40 @@ use soroban_sdk::{assert_with_error, xdr::FromXdr, Env};
12
15
  #[contract_trait]
13
16
  pub trait Upgradeable: UpgradeableInternal + Auth {
14
17
  /// Upgrades the contract to new WASM bytecode.
15
- /// Sets a migration flag that must be cleared by calling `migrate`.
16
18
  #[only_auth]
17
19
  fn upgrade(env: &soroban_sdk::Env, new_wasm_hash: &soroban_sdk::BytesN<32>) {
18
- UpgradeableStorage::set_migrating(env, &true);
19
- env.deployer().update_current_contract_wasm(new_wasm_hash.clone());
20
+ upgrade(env, new_wasm_hash);
20
21
  }
21
22
 
22
23
  /// Runs migration logic after an upgrade.
23
- /// Parses XDR-encoded `migration_data` and calls `__migrate`. Clears the migration flag on success.
24
24
  #[only_auth]
25
25
  fn migrate(env: &soroban_sdk::Env, migration_data: &soroban_sdk::Bytes) {
26
- assert_with_error!(env, UpgradeableStorage::migrating(env), UpgradeableError::MigrationNotAllowed);
26
+ migrate::<Self>(env, migration_data);
27
+ }
28
+ }
27
29
 
28
- // Parse the migration data and call the internal migration logic
29
- let parsed_data = Self::MigrationData::from_xdr(env, migration_data)
30
- .ok()
31
- .unwrap_or_panic(env, UpgradeableError::InvalidMigrationData);
32
- Self::__migrate(env, &parsed_data);
30
+ /// Trait for contracts with upgrade and migration support (RBAC-based).
31
+ ///
32
+ /// Same two-phase upgrade pattern as [`Upgradeable`], but access control uses
33
+ /// `UPGRADER_ROLE` instead of Auth. Requires implementing [`UpgradeableInternal`]
34
+ /// and [`RoleBasedAccessControl`].
35
+ #[contract_trait]
36
+ pub trait UpgradeableRbac: UpgradeableInternal + RoleBasedAccessControl {
37
+ /// Upgrades the contract to new WASM bytecode.
38
+ #[only_role(operator, UPGRADER_ROLE)]
39
+ fn upgrade(env: &soroban_sdk::Env, new_wasm_hash: &soroban_sdk::BytesN<32>, operator: &soroban_sdk::Address) {
40
+ upgrade(env, new_wasm_hash);
41
+ }
33
42
 
34
- // Clear the migration flag after migration is successful
35
- UpgradeableStorage::set_migrating(env, &false);
43
+ /// Runs migration logic after an upgrade.
44
+ #[only_role(operator, UPGRADER_ROLE)]
45
+ fn migrate(env: &soroban_sdk::Env, migration_data: &soroban_sdk::Bytes, operator: &soroban_sdk::Address) {
46
+ migrate::<Self>(env, migration_data);
36
47
  }
37
48
  }
38
49
 
39
50
  /// Trait for defining contract-specific migration logic.
40
- /// Must be implemented by contracts using [`Upgradeable`].
51
+ /// Must be implemented by contracts using [`Upgradeable`] or [`UpgradeableRbac`].
41
52
  pub trait UpgradeableInternal {
42
53
  /// The XDR-decodable type for migration data. Use `()` if not needed.
43
54
  type MigrationData: FromXdr;
@@ -46,6 +57,38 @@ pub trait UpgradeableInternal {
46
57
  fn __migrate(env: &Env, migration_data: &Self::MigrationData);
47
58
  }
48
59
 
60
+ // ============================================
61
+ // Helper Functions
62
+ // ============================================
63
+
64
+ /// Core upgrade logic: set migrating flag and update WASM.
65
+ ///
66
+ /// # Arguments
67
+ /// - `new_wasm_hash` - The hash of the new WASM bytecode
68
+ fn upgrade(env: &Env, new_wasm_hash: &BytesN<32>) {
69
+ UpgradeableStorage::set_migrating(env, &true);
70
+ env.deployer().update_current_contract_wasm(new_wasm_hash.clone());
71
+ }
72
+
73
+ /// Core migration logic: parse migration data, call `__migrate`, clear flag.
74
+ ///
75
+ /// # Arguments
76
+ /// - `migration_data` - The migration data
77
+ ///
78
+ /// # Panics
79
+ /// - `MigrationNotAllowed` if no migration is in progress
80
+ /// - `InvalidMigrationData` if the migration data cannot be parsed into the contract's `MigrationData` type
81
+ fn migrate<T: UpgradeableInternal>(env: &Env, migration_data: &Bytes) {
82
+ assert_with_error!(env, UpgradeableStorage::migrating(env), UpgradeableError::MigrationNotAllowed);
83
+
84
+ let parsed_data = T::MigrationData::from_xdr(env, migration_data)
85
+ .ok()
86
+ .unwrap_or_panic(env, UpgradeableError::InvalidMigrationData);
87
+ T::__migrate(env, &parsed_data);
88
+
89
+ UpgradeableStorage::set_migrating(env, &false);
90
+ }
91
+
49
92
  // ============================================
50
93
  // Storage
51
94
  // ============================================
@@ -76,14 +76,14 @@ The `initialize_oapp` function:
76
76
  Before sending or receiving messages, configure peers for each destination chain:
77
77
 
78
78
  ```rust
79
- // Set a peer (owner only)
80
- oapp.set_peer(dst_eid, peer_address_bytes32);
79
+ // Set a peer (owner only). Pass owner as operator (reserved for future RBAC).
80
+ oapp.set_peer(env, dst_eid, &Some(peer_address_bytes32), &owner);
81
81
 
82
82
  // Remove a peer
83
- oapp.set_peer(dst_eid, None);
83
+ oapp.set_peer(env, dst_eid, &None, &owner);
84
84
 
85
85
  // Query a peer
86
- let peer = oapp.peer(dst_eid);
86
+ let peer = oapp.peer(env, dst_eid);
87
87
  ```
88
88
 
89
89
  Peers are stored as `BytesN<32>` to maintain cross-chain address compatibility.
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@layerzerolabs/protocol-stellar-v2",
3
- "version": "0.2.40",
3
+ "version": "0.2.41",
4
4
  "private": false,
5
5
  "devDependencies": {
6
6
  "@types/node": "^22.18.6",
7
7
  "tsx": "^4.19.3",
8
8
  "typescript": "^5.8.2",
9
- "@layerzerolabs/common-node-utils": "0.2.40",
10
- "@layerzerolabs/vm-tooling-stellar": "0.2.40"
9
+ "@layerzerolabs/common-node-utils": "0.2.41",
10
+ "@layerzerolabs/vm-tooling-stellar": "0.2.41"
11
11
  },
12
12
  "publishConfig": {
13
13
  "access": "restricted",
@@ -25,7 +25,6 @@
25
25
  "generate:sdk": "pnpm exec lz-tool --script \"cargo run -p ts-bindings-gen\" stellar",
26
26
  "lint": "pnpm exec lz-tool --script \"cargo clippy -- -D warnings\" stellar",
27
27
  "lint:fix": "pnpm exec lz-tool --script \"cargo clippy --fix --allow-dirty --allow-staged && cargo fmt\" stellar",
28
- "setup:toolchain": "pnpm exec lz-tool sync-toolchain",
29
28
  "test": "pnpm exec lz-tool --script \"cargo nextest run\" stellar"
30
29
  }
31
30
  }