@layerzerolabs/protocol-stellar-v2 0.2.39 → 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.
- package/.turbo/turbo-build.log +226 -313
- package/.turbo/turbo-lint.log +98 -227
- package/.turbo/turbo-test.log +1803 -1954
- package/contracts/common-macros/src/lib.rs +38 -15
- package/contracts/common-macros/src/lz_contract.rs +12 -21
- package/contracts/common-macros/src/tests/lz_contract.rs +17 -8
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__lz_contract__snapshot_generated_lz_contract_code.snap +20 -0
- package/contracts/common-macros/src/upgradeable.rs +37 -30
- package/contracts/endpoint-v2/src/endpoint_v2.rs +4 -3
- package/contracts/endpoint-v2/src/errors.rs +2 -2
- package/contracts/endpoint-v2/src/messaging_channel.rs +11 -0
- package/contracts/endpoint-v2/src/messaging_composer.rs +1 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +12 -25
- package/contracts/endpoint-v2/src/tests/endpoint_v2/initializable.rs +4 -4
- package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +50 -10
- package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +6 -35
- package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +2 -2
- package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +50 -1
- package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +78 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/insert_and_drain_pending_nonces.rs +272 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +10 -5
- package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +30 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +22 -1
- package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +13 -11
- package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +13 -10
- package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +15 -11
- package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +3 -2
- package/contracts/macro-integration-tests/tests/runtime/ownable/two_step_transfer.rs +14 -12
- package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +3 -9
- package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_invalid_inner_option.stderr +24 -1
- package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_missing_internal.stderr +3 -3
- package/contracts/macro-integration-tests/tests/ui/lz_contract/pass/upgradeable_rbac.rs +44 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +3 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +3 -0
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/basic.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/attr_args.stderr +1 -1
- package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_auth_trait.stderr +2 -2
- package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_upgradeable_internal.stderr +2 -2
- package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/rbac.rs +44 -0
- package/contracts/oapps/counter/integration_tests/utils.rs +5 -3
- package/contracts/oapps/counter/src/tests/mod.rs +16 -1
- package/contracts/oapps/counter/src/tests/test_counter.rs +5 -2
- package/contracts/oapps/oapp/src/oapp_core.rs +21 -7
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +7 -5
- package/contracts/oapps/oapp/src/tests/mod.rs +21 -0
- package/contracts/oapps/oapp/src/tests/oapp_core.rs +12 -10
- package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +11 -7
- package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +4 -2
- package/contracts/oapps/oapp/src/tests/oapp_sender.rs +3 -2
- package/contracts/oapps/oapp/src/tests/test_macros.rs +15 -0
- package/contracts/oapps/oapp-macros/src/generators.rs +6 -0
- package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +15 -0
- package/contracts/oapps/oft/integration-tests/setup.rs +22 -4
- package/contracts/oapps/oft/integration-tests/utils.rs +94 -13
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +23 -10
- package/contracts/oapps/oft/src/extensions/pausable.rs +31 -10
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +9 -4
- package/contracts/oapps/oft/src/oft.rs +1 -2
- package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +39 -27
- package/contracts/oapps/oft/src/tests/extensions/pausable.rs +38 -24
- package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +87 -69
- package/contracts/oapps/oft-core/integration-tests/setup.rs +27 -3
- package/contracts/oapps/oft-core/src/oft_core.rs +10 -5
- package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +20 -20
- package/contracts/oapps/oft-core/src/tests/test_utils.rs +31 -3
- package/contracts/upgrader/src/lib.rs +67 -30
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract3.wasm +0 -0
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract4.wasm +0 -0
- package/contracts/upgrader/src/tests/test_upgrader.rs +50 -4
- package/contracts/utils/src/ownable.rs +16 -5
- package/contracts/utils/src/tests/ownable.rs +39 -39
- package/contracts/utils/src/upgradeable.rs +60 -17
- package/docs/oapp-guide.md +4 -4
- package/package.json +3 -4
- package/sdk/.turbo/turbo-test.log +381 -366
- package/sdk/dist/generated/bml.d.ts +4 -4
- package/sdk/dist/generated/bml.js +6 -6
- package/sdk/dist/generated/counter.d.ts +158 -12
- package/sdk/dist/generated/counter.js +32 -12
- package/sdk/dist/generated/dvn.d.ts +4 -6
- package/sdk/dist/generated/dvn.js +8 -8
- package/sdk/dist/generated/dvn_fee_lib.d.ts +8 -10
- package/sdk/dist/generated/dvn_fee_lib.js +8 -8
- package/sdk/dist/generated/endpoint.d.ts +9 -9
- package/sdk/dist/generated/endpoint.js +9 -9
- package/sdk/dist/generated/executor.d.ts +9 -11
- package/sdk/dist/generated/executor.js +11 -11
- package/sdk/dist/generated/executor_fee_lib.d.ts +9 -11
- package/sdk/dist/generated/executor_fee_lib.js +11 -11
- package/sdk/dist/generated/executor_helper.d.ts +4 -4
- package/sdk/dist/generated/executor_helper.js +6 -6
- package/sdk/dist/generated/layerzero_view.d.ts +9 -11
- package/sdk/dist/generated/layerzero_view.js +11 -11
- package/sdk/dist/generated/oft.d.ts +194 -27
- package/sdk/dist/generated/oft.js +44 -22
- package/sdk/dist/generated/price_feed.d.ts +8 -10
- package/sdk/dist/generated/price_feed.js +8 -8
- package/sdk/dist/generated/sac_manager.d.ts +8 -8
- package/sdk/dist/generated/sac_manager.js +6 -6
- package/sdk/dist/generated/sml.d.ts +9 -9
- package/sdk/dist/generated/sml.js +9 -9
- package/sdk/dist/generated/treasury.d.ts +9 -9
- package/sdk/dist/generated/treasury.js +9 -9
- package/sdk/dist/generated/uln302.d.ts +9 -9
- package/sdk/dist/generated/uln302.js +9 -9
- package/sdk/dist/generated/upgrader.d.ts +25 -16
- package/sdk/dist/generated/upgrader.js +5 -5
- package/sdk/package.json +1 -1
- package/sdk/test/counter-sml.test.ts +20 -0
- package/sdk/test/counter-uln.test.ts +20 -0
- package/sdk/test/oft-sml.test.ts +22 -0
- package/sdk/test/upgrader.test.ts +1 -0
- package/turbo.json +1 -8
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
//! Utility functions for OFT-STD integration tests.
|
|
2
2
|
|
|
3
|
-
use crate::extensions::rate_limiter::{Direction, Mode, RateLimitConfig};
|
|
3
|
+
use crate::extensions::rate_limiter::{Direction, Mode, RateLimitConfig, RATE_LIMITER_ADMIN_ROLE};
|
|
4
|
+
use crate::extensions::oft_fee::FEE_ADMIN_ROLE;
|
|
5
|
+
use crate::extensions::pausable::{PAUSER_ROLE, UNPAUSER_ROLE};
|
|
4
6
|
use crate::integration_tests::setup::{decode_packet, ChainSetup};
|
|
5
7
|
use crate::MintableClient;
|
|
6
8
|
use endpoint_v2::{MessagingFee, Origin, OutboundPacket};
|
|
@@ -13,7 +15,6 @@ use soroban_sdk::{
|
|
|
13
15
|
xdr::ToXdr,
|
|
14
16
|
Address, Bytes, BytesN, Env, IntoVal, Map, Symbol, Val, Vec,
|
|
15
17
|
};
|
|
16
|
-
|
|
17
18
|
// ============================================================================
|
|
18
19
|
// Address Conversion Utilities
|
|
19
20
|
// ============================================================================
|
|
@@ -356,16 +357,44 @@ pub fn token_balance(env: &Env, token: &Address, account: &Address) -> i128 {
|
|
|
356
357
|
// ============================================================================
|
|
357
358
|
|
|
358
359
|
pub fn set_paused(env: &Env, chain: &ChainSetup<'_>, paused: bool) {
|
|
360
|
+
// `pause` / `unpause` are protected by RBAC (`PAUSER_ROLE` / `UNPAUSER_ROLE`). Grant them to owner for tests.
|
|
361
|
+
let pauser = Symbol::new(env, PAUSER_ROLE);
|
|
362
|
+
let unpauser = Symbol::new(env, UNPAUSER_ROLE);
|
|
359
363
|
env.mock_auths(&[MockAuth {
|
|
360
364
|
address: &chain.owner,
|
|
361
365
|
invoke: &MockAuthInvoke {
|
|
362
366
|
contract: &chain.oft.address,
|
|
363
|
-
fn_name: "
|
|
364
|
-
args: (&
|
|
367
|
+
fn_name: "grant_role",
|
|
368
|
+
args: (&chain.owner, &pauser, &chain.owner).into_val(env),
|
|
365
369
|
sub_invokes: &[],
|
|
366
370
|
},
|
|
367
371
|
}]);
|
|
368
|
-
chain.oft.
|
|
372
|
+
chain.oft.grant_role(&chain.owner, &pauser, &chain.owner);
|
|
373
|
+
env.mock_auths(&[MockAuth {
|
|
374
|
+
address: &chain.owner,
|
|
375
|
+
invoke: &MockAuthInvoke {
|
|
376
|
+
contract: &chain.oft.address,
|
|
377
|
+
fn_name: "grant_role",
|
|
378
|
+
args: (&chain.owner, &unpauser, &chain.owner).into_val(env),
|
|
379
|
+
sub_invokes: &[],
|
|
380
|
+
},
|
|
381
|
+
}]);
|
|
382
|
+
chain.oft.grant_role(&chain.owner, &unpauser, &chain.owner);
|
|
383
|
+
|
|
384
|
+
env.mock_auths(&[MockAuth {
|
|
385
|
+
address: &chain.owner,
|
|
386
|
+
invoke: &MockAuthInvoke {
|
|
387
|
+
contract: &chain.oft.address,
|
|
388
|
+
fn_name: if paused { "pause" } else { "unpause" },
|
|
389
|
+
args: (&chain.owner,).into_val(env),
|
|
390
|
+
sub_invokes: &[],
|
|
391
|
+
},
|
|
392
|
+
}]);
|
|
393
|
+
if paused {
|
|
394
|
+
chain.oft.pause(&chain.owner);
|
|
395
|
+
} else {
|
|
396
|
+
chain.oft.unpause(&chain.owner);
|
|
397
|
+
}
|
|
369
398
|
}
|
|
370
399
|
|
|
371
400
|
pub fn is_paused(chain: &ChainSetup<'_>) -> bool {
|
|
@@ -377,45 +406,84 @@ pub fn is_paused(chain: &ChainSetup<'_>) -> bool {
|
|
|
377
406
|
// ============================================================================
|
|
378
407
|
|
|
379
408
|
pub fn set_fee_deposit_address(env: &Env, chain: &ChainSetup<'_>, deposit_address: &Address) {
|
|
409
|
+
// `set_fee_deposit_address` is protected by RBAC (`FEE_ADMIN_ROLE`). Grant it to owner for tests.
|
|
410
|
+
let role = Symbol::new(env, FEE_ADMIN_ROLE);
|
|
411
|
+
env.mock_auths(&[MockAuth {
|
|
412
|
+
address: &chain.owner,
|
|
413
|
+
invoke: &MockAuthInvoke {
|
|
414
|
+
contract: &chain.oft.address,
|
|
415
|
+
fn_name: "grant_role",
|
|
416
|
+
args: (&chain.owner, &role, &chain.owner).into_val(env),
|
|
417
|
+
sub_invokes: &[],
|
|
418
|
+
},
|
|
419
|
+
}]);
|
|
420
|
+
chain.oft.grant_role(&chain.owner, &role, &chain.owner);
|
|
421
|
+
|
|
380
422
|
let deposit_address_opt = Some(deposit_address.clone());
|
|
381
423
|
env.mock_auths(&[MockAuth {
|
|
382
424
|
address: &chain.owner,
|
|
383
425
|
invoke: &MockAuthInvoke {
|
|
384
426
|
contract: &chain.oft.address,
|
|
385
427
|
fn_name: "set_fee_deposit_address",
|
|
386
|
-
args: (&deposit_address_opt,).into_val(env),
|
|
428
|
+
args: (&deposit_address_opt, &chain.owner).into_val(env),
|
|
387
429
|
sub_invokes: &[],
|
|
388
430
|
},
|
|
389
431
|
}]);
|
|
390
|
-
chain.oft.set_fee_deposit_address(&deposit_address_opt);
|
|
432
|
+
chain.oft.set_fee_deposit_address(&deposit_address_opt, &chain.owner);
|
|
391
433
|
}
|
|
392
434
|
|
|
393
435
|
pub fn set_default_fee_bps(env: &Env, chain: &ChainSetup<'_>, fee_bps: u32) {
|
|
436
|
+
// `set_default_fee_bps` is protected by RBAC (`FEE_ADMIN_ROLE`). Grant it to owner for tests.
|
|
437
|
+
let role = Symbol::new(env, FEE_ADMIN_ROLE);
|
|
438
|
+
env.mock_auths(&[MockAuth {
|
|
439
|
+
address: &chain.owner,
|
|
440
|
+
invoke: &MockAuthInvoke {
|
|
441
|
+
contract: &chain.oft.address,
|
|
442
|
+
fn_name: "grant_role",
|
|
443
|
+
args: (&chain.owner, &role, &chain.owner).into_val(env),
|
|
444
|
+
sub_invokes: &[],
|
|
445
|
+
},
|
|
446
|
+
}]);
|
|
447
|
+
chain.oft.grant_role(&chain.owner, &role, &chain.owner);
|
|
448
|
+
|
|
394
449
|
let fee_bps_opt = Some(fee_bps);
|
|
395
450
|
env.mock_auths(&[MockAuth {
|
|
396
451
|
address: &chain.owner,
|
|
397
452
|
invoke: &MockAuthInvoke {
|
|
398
453
|
contract: &chain.oft.address,
|
|
399
454
|
fn_name: "set_default_fee_bps",
|
|
400
|
-
args: (&fee_bps_opt,).into_val(env),
|
|
455
|
+
args: (&fee_bps_opt, &chain.owner).into_val(env),
|
|
401
456
|
sub_invokes: &[],
|
|
402
457
|
},
|
|
403
458
|
}]);
|
|
404
|
-
chain.oft.set_default_fee_bps(&fee_bps_opt);
|
|
459
|
+
chain.oft.set_default_fee_bps(&fee_bps_opt, &chain.owner);
|
|
405
460
|
}
|
|
406
461
|
|
|
407
462
|
pub fn set_fee_bps(env: &Env, chain: &ChainSetup<'_>, dst_eid: u32, fee_bps: u32) {
|
|
463
|
+
// `set_fee_bps` is protected by RBAC (`FEE_ADMIN_ROLE`). Grant it to owner for tests.
|
|
464
|
+
let role = Symbol::new(env, FEE_ADMIN_ROLE);
|
|
465
|
+
env.mock_auths(&[MockAuth {
|
|
466
|
+
address: &chain.owner,
|
|
467
|
+
invoke: &MockAuthInvoke {
|
|
468
|
+
contract: &chain.oft.address,
|
|
469
|
+
fn_name: "grant_role",
|
|
470
|
+
args: (&chain.owner, &role, &chain.owner).into_val(env),
|
|
471
|
+
sub_invokes: &[],
|
|
472
|
+
},
|
|
473
|
+
}]);
|
|
474
|
+
chain.oft.grant_role(&chain.owner, &role, &chain.owner);
|
|
475
|
+
|
|
408
476
|
let fee_bps_opt = Some(fee_bps);
|
|
409
477
|
env.mock_auths(&[MockAuth {
|
|
410
478
|
address: &chain.owner,
|
|
411
479
|
invoke: &MockAuthInvoke {
|
|
412
480
|
contract: &chain.oft.address,
|
|
413
481
|
fn_name: "set_fee_bps",
|
|
414
|
-
args: (&dst_eid, &fee_bps_opt).into_val(env),
|
|
482
|
+
args: (&dst_eid, &fee_bps_opt, &chain.owner).into_val(env),
|
|
415
483
|
sub_invokes: &[],
|
|
416
484
|
},
|
|
417
485
|
}]);
|
|
418
|
-
chain.oft.set_fee_bps(&dst_eid, &fee_bps_opt);
|
|
486
|
+
chain.oft.set_fee_bps(&dst_eid, &fee_bps_opt, &chain.owner);
|
|
419
487
|
}
|
|
420
488
|
|
|
421
489
|
// ============================================================================
|
|
@@ -442,17 +510,30 @@ pub fn set_rate_limit_with_mode(
|
|
|
442
510
|
window_seconds: u64,
|
|
443
511
|
mode: Mode,
|
|
444
512
|
) {
|
|
513
|
+
// `set_rate_limit` is protected by RBAC (`RATE_LIMITER_ADMIN_ROLE`). Grant it to owner for tests.
|
|
514
|
+
let role = Symbol::new(env, RATE_LIMITER_ADMIN_ROLE);
|
|
515
|
+
env.mock_auths(&[MockAuth {
|
|
516
|
+
address: &chain.owner,
|
|
517
|
+
invoke: &MockAuthInvoke {
|
|
518
|
+
contract: &chain.oft.address,
|
|
519
|
+
fn_name: "grant_role",
|
|
520
|
+
args: (&chain.owner, &role, &chain.owner).into_val(env),
|
|
521
|
+
sub_invokes: &[],
|
|
522
|
+
},
|
|
523
|
+
}]);
|
|
524
|
+
chain.oft.grant_role(&chain.owner, &role, &chain.owner);
|
|
525
|
+
|
|
445
526
|
let config = Some(RateLimitConfig { limit, window_seconds, mode });
|
|
446
527
|
env.mock_auths(&[MockAuth {
|
|
447
528
|
address: &chain.owner,
|
|
448
529
|
invoke: &MockAuthInvoke {
|
|
449
530
|
contract: &chain.oft.address,
|
|
450
531
|
fn_name: "set_rate_limit",
|
|
451
|
-
args: (direction, &dst_eid, &config).into_val(env),
|
|
532
|
+
args: (direction, &dst_eid, &config, &chain.owner).into_val(env),
|
|
452
533
|
sub_invokes: &[],
|
|
453
534
|
},
|
|
454
535
|
}]);
|
|
455
|
-
chain.oft.set_rate_limit(direction, &dst_eid, &config);
|
|
536
|
+
chain.oft.set_rate_limit(direction, &dst_eid, &config, &chain.owner);
|
|
456
537
|
}
|
|
457
538
|
|
|
458
539
|
pub fn rate_limit_capacity(chain: &ChainSetup<'_>, direction: &Direction, eid: u32) -> i128 {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
use common_macros::{contract_error, contract_trait,
|
|
1
|
+
use common_macros::{contract_error, contract_trait, only_role, storage};
|
|
2
2
|
use soroban_sdk::{assert_with_error, contractevent, token::TokenClient, Address, Env};
|
|
3
|
-
use utils::{
|
|
3
|
+
use utils::{option_ext::OptionExt, rbac::RoleBasedAccessControl};
|
|
4
|
+
|
|
5
|
+
/// Role for fee configuration (set_default_fee_bps, set_fee_bps, set_fee_deposit_address).
|
|
6
|
+
pub const FEE_ADMIN_ROLE: &str = "FEE_ADMIN_ROLE";
|
|
4
7
|
|
|
5
8
|
/// Base fee in basis points (10,000 BPS = 100%)
|
|
6
9
|
/// Used as denominator in fee calculations
|
|
@@ -69,7 +72,7 @@ pub struct FeeDepositAddressSet {
|
|
|
69
72
|
// =========================================================================
|
|
70
73
|
|
|
71
74
|
#[contract_trait]
|
|
72
|
-
pub trait OFTFee: OFTFeeInternal +
|
|
75
|
+
pub trait OFTFee: OFTFeeInternal + RoleBasedAccessControl {
|
|
73
76
|
// =========================================================================
|
|
74
77
|
// Management Functions
|
|
75
78
|
// =========================================================================
|
|
@@ -79,8 +82,9 @@ pub trait OFTFee: OFTFeeInternal + Auth {
|
|
|
79
82
|
/// - `Some(n)`: sets the default fee to `n` basis points (must be >0 and <=10,000).
|
|
80
83
|
/// - `Some(0)`: rejected — use `None` to remove the default fee instead.
|
|
81
84
|
/// - `None`: removes the default fee (effective rate becomes 0).
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
/// * `operator` - The address that must have FEE_ADMIN_ROLE
|
|
86
|
+
#[only_role(operator, FEE_ADMIN_ROLE)]
|
|
87
|
+
fn set_default_fee_bps(env: &soroban_sdk::Env, default_fee_bps: &Option<u32>, operator: &soroban_sdk::Address) {
|
|
84
88
|
Self::__set_default_fee_bps(env, default_fee_bps);
|
|
85
89
|
}
|
|
86
90
|
|
|
@@ -92,14 +96,23 @@ pub trait OFTFee: OFTFeeInternal + Auth {
|
|
|
92
96
|
/// # Arguments
|
|
93
97
|
/// * `dst_eid` - The destination endpoint ID
|
|
94
98
|
/// * `fee_bps` - The fee rate (0-10,000), or None to remove the fee configuration
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
/// * `operator` - The address that must have FEE_ADMIN_ROLE
|
|
100
|
+
#[only_role(operator, FEE_ADMIN_ROLE)]
|
|
101
|
+
fn set_fee_bps(env: &soroban_sdk::Env, dst_eid: u32, fee_bps: &Option<u32>, operator: &soroban_sdk::Address) {
|
|
97
102
|
Self::__set_fee_bps(env, dst_eid, fee_bps);
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
/// Sets or removes the address where collected fees will be deposited.
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
///
|
|
107
|
+
/// # Arguments
|
|
108
|
+
/// * `fee_deposit_address` - The address to deposit fees to, or None to remove the fee deposit address
|
|
109
|
+
/// * `operator` - The address that must have FEE_ADMIN_ROLE
|
|
110
|
+
#[only_role(operator, FEE_ADMIN_ROLE)]
|
|
111
|
+
fn set_fee_deposit_address(
|
|
112
|
+
env: &soroban_sdk::Env,
|
|
113
|
+
fee_deposit_address: &Option<soroban_sdk::Address>,
|
|
114
|
+
operator: &soroban_sdk::Address,
|
|
115
|
+
) {
|
|
103
116
|
Self::__set_fee_deposit_address(env, fee_deposit_address);
|
|
104
117
|
}
|
|
105
118
|
|
|
@@ -134,7 +147,7 @@ pub trait OFTFee: OFTFeeInternal + Auth {
|
|
|
134
147
|
}
|
|
135
148
|
|
|
136
149
|
/// Internal trait for OFT fee operations used by OFT hooks.
|
|
137
|
-
/// Contains only truly internal methods that are called from
|
|
150
|
+
/// Contains only truly internal methods that are called from OFTFee implementations.
|
|
138
151
|
pub trait OFTFeeInternal {
|
|
139
152
|
// =========================================================================
|
|
140
153
|
// OFT Hooks
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
use common_macros::{contract_error, contract_trait,
|
|
1
|
+
use common_macros::{contract_error, contract_trait, only_role, storage};
|
|
2
2
|
use soroban_sdk::{assert_with_error, contractevent, Env};
|
|
3
|
-
use utils::
|
|
3
|
+
use utils::rbac::RoleBasedAccessControl;
|
|
4
|
+
|
|
5
|
+
/// Role for pausing the contract.
|
|
6
|
+
pub const PAUSER_ROLE: &str = "PAUSER_ROLE";
|
|
7
|
+
|
|
8
|
+
/// Role for unpausing the contract.
|
|
9
|
+
pub const UNPAUSER_ROLE: &str = "UNPAUSER_ROLE";
|
|
4
10
|
|
|
5
11
|
// =========================================================================
|
|
6
12
|
// Storage
|
|
@@ -37,18 +43,33 @@ pub struct PausedSet {
|
|
|
37
43
|
// =========================================================================
|
|
38
44
|
|
|
39
45
|
#[contract_trait]
|
|
40
|
-
pub trait OFTPausable: OFTPausableInternal +
|
|
41
|
-
|
|
46
|
+
pub trait OFTPausable: OFTPausableInternal + RoleBasedAccessControl {
|
|
47
|
+
// =========================================================================
|
|
48
|
+
// Management Functions
|
|
49
|
+
// =========================================================================
|
|
50
|
+
|
|
51
|
+
/// Pauses the OFT. When paused, the OFT will reject new send/receive/quote_send/quote_oft operations.
|
|
42
52
|
///
|
|
43
|
-
///
|
|
53
|
+
/// # Arguments
|
|
54
|
+
/// * `operator` - The address that must have PAUSER_ROLE
|
|
55
|
+
#[only_role(operator, PAUSER_ROLE)]
|
|
56
|
+
fn pause(env: &soroban_sdk::Env, operator: &soroban_sdk::Address) {
|
|
57
|
+
Self::__set_paused(env, true);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Unpauses the OFT.
|
|
44
61
|
///
|
|
45
62
|
/// # Arguments
|
|
46
|
-
/// * `
|
|
47
|
-
#[
|
|
48
|
-
fn
|
|
49
|
-
Self::__set_paused(env,
|
|
63
|
+
/// * `operator` - The address that must have UNPAUSER_ROLE
|
|
64
|
+
#[only_role(operator, UNPAUSER_ROLE)]
|
|
65
|
+
fn unpause(env: &soroban_sdk::Env, operator: &soroban_sdk::Address) {
|
|
66
|
+
Self::__set_paused(env, false);
|
|
50
67
|
}
|
|
51
68
|
|
|
69
|
+
// =========================================================================
|
|
70
|
+
// View Functions
|
|
71
|
+
// =========================================================================
|
|
72
|
+
|
|
52
73
|
/// Returns the paused state of the OFT.
|
|
53
74
|
fn is_paused(env: &soroban_sdk::Env) -> bool {
|
|
54
75
|
Self::__is_paused(env)
|
|
@@ -56,7 +77,7 @@ pub trait OFTPausable: OFTPausableInternal + Auth {
|
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
/// Internal trait for pausable operations used by OFT hooks.
|
|
59
|
-
/// Contains only truly internal methods that are called from
|
|
80
|
+
/// Contains only truly internal methods that are called from OFTPausable implementations.
|
|
60
81
|
pub trait OFTPausableInternal {
|
|
61
82
|
// =========================================================================
|
|
62
83
|
// OFT Hooks
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
use crate as oft;
|
|
2
|
-
use common_macros::{contract_error, contract_trait,
|
|
2
|
+
use common_macros::{contract_error, contract_trait, only_role, storage};
|
|
3
3
|
use soroban_sdk::{assert_with_error, contractevent, contracttype, Env};
|
|
4
|
-
use utils::
|
|
4
|
+
use utils::rbac::RoleBasedAccessControl;
|
|
5
|
+
|
|
6
|
+
/// Role for rate limiter configuration (set_rate_limit).
|
|
7
|
+
pub const RATE_LIMITER_ADMIN_ROLE: &str = "RATE_LIMITER_ADMIN_ROLE";
|
|
5
8
|
|
|
6
9
|
// =========================================================================
|
|
7
10
|
// Types
|
|
@@ -94,7 +97,7 @@ pub struct RateLimitSet {
|
|
|
94
97
|
// =========================================================================
|
|
95
98
|
|
|
96
99
|
#[contract_trait]
|
|
97
|
-
pub trait RateLimiter: RateLimiterInternal +
|
|
100
|
+
pub trait RateLimiter: RateLimiterInternal + RoleBasedAccessControl {
|
|
98
101
|
// =========================================================================
|
|
99
102
|
// Management Functions
|
|
100
103
|
// =========================================================================
|
|
@@ -105,12 +108,14 @@ pub trait RateLimiter: RateLimiterInternal + Auth {
|
|
|
105
108
|
/// * `direction` - The direction (Inbound or Outbound)
|
|
106
109
|
/// * `eid` - The endpoint ID
|
|
107
110
|
/// * `config` - The rate limit configuration, or None to remove the rate limit
|
|
108
|
-
|
|
111
|
+
/// * `operator` - The address that must have RATE_LIMITER_ADMIN_ROLE
|
|
112
|
+
#[only_role(operator, RATE_LIMITER_ADMIN_ROLE)]
|
|
109
113
|
fn set_rate_limit(
|
|
110
114
|
env: &soroban_sdk::Env,
|
|
111
115
|
direction: &oft::rate_limiter::Direction,
|
|
112
116
|
eid: u32,
|
|
113
117
|
config: &Option<oft::rate_limiter::RateLimitConfig>,
|
|
118
|
+
operator: &soroban_sdk::Address,
|
|
114
119
|
) {
|
|
115
120
|
Self::__set_rate_limit(env, direction, eid, config);
|
|
116
121
|
}
|
|
@@ -42,11 +42,10 @@ impl OFT {
|
|
|
42
42
|
token: &Address,
|
|
43
43
|
shared_decimals: u32,
|
|
44
44
|
oft_type: OftType,
|
|
45
|
-
owner: &Address,
|
|
46
45
|
endpoint: &Address,
|
|
47
46
|
delegate: &Address,
|
|
48
47
|
) {
|
|
49
|
-
Self::__initialize_oft(env, token, shared_decimals,
|
|
48
|
+
Self::__initialize_oft(env, token, shared_decimals, delegate, endpoint, delegate);
|
|
50
49
|
OFTStorage::set_oft_type(env, &oft_type);
|
|
51
50
|
}
|
|
52
51
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
extern crate std;
|
|
2
2
|
|
|
3
3
|
use crate::extensions::oft_fee::{OFTFee, OFTFeeError, OFTFeeInternal};
|
|
4
|
+
use crate::extensions::oft_fee::FEE_ADMIN_ROLE;
|
|
4
5
|
use soroban_sdk::{
|
|
5
6
|
contract, contractimpl,
|
|
6
7
|
testutils::{Address as _, MockAuth, MockAuthInvoke},
|
|
7
8
|
token::{StellarAssetClient, TokenClient},
|
|
8
|
-
Address, Env, IntoVal,
|
|
9
|
+
Address, Env, IntoVal, Symbol,
|
|
9
10
|
};
|
|
10
11
|
use utils::auth::Auth;
|
|
12
|
+
use utils::rbac::{grant_role_no_auth, RoleBasedAccessControl};
|
|
11
13
|
|
|
12
14
|
// ============================================================================
|
|
13
15
|
// Test Contract
|
|
@@ -27,8 +29,17 @@ impl OFTFeeInternal for FeeTestContract {}
|
|
|
27
29
|
#[contractimpl(contracttrait)]
|
|
28
30
|
impl OFTFee for FeeTestContract {}
|
|
29
31
|
|
|
32
|
+
#[contractimpl(contracttrait)]
|
|
33
|
+
impl RoleBasedAccessControl for FeeTestContract {}
|
|
34
|
+
|
|
30
35
|
#[contractimpl]
|
|
31
36
|
impl FeeTestContract {
|
|
37
|
+
/// Test-only: grants FEE_ADMIN_ROLE to the contract.
|
|
38
|
+
pub fn init_roles(env: Env) {
|
|
39
|
+
let contract_id = env.current_contract_address();
|
|
40
|
+
grant_role_no_auth(&env, &contract_id, &Symbol::new(&env, FEE_ADMIN_ROLE), &contract_id);
|
|
41
|
+
}
|
|
42
|
+
|
|
32
43
|
pub fn fee_view(env: Env, dst_eid: u32, amount_ld: i128) -> i128 {
|
|
33
44
|
<Self as OFTFeeInternal>::__fee_view(&env, dst_eid, amount_ld)
|
|
34
45
|
}
|
|
@@ -59,6 +70,7 @@ fn setup() -> TestSetup {
|
|
|
59
70
|
|
|
60
71
|
let contract_id = env.register(FeeTestContract, ());
|
|
61
72
|
let client = FeeTestContractClient::new(&env, &contract_id);
|
|
73
|
+
client.init_roles();
|
|
62
74
|
|
|
63
75
|
let token_admin = Address::generate(&env);
|
|
64
76
|
let sac = env.register_stellar_asset_contract_v2(token_admin.clone());
|
|
@@ -94,9 +106,9 @@ fn test_fee_deposit_address_returns_none_when_unset() {
|
|
|
94
106
|
|
|
95
107
|
#[test]
|
|
96
108
|
fn test_fee_view_nonzero_fee_errors_when_deposit_address_unset() {
|
|
97
|
-
let TestSetup { client, .. } = setup();
|
|
109
|
+
let TestSetup { client, contract_id, .. } = setup();
|
|
98
110
|
|
|
99
|
-
client.set_default_fee_bps(&Some(100u32));
|
|
111
|
+
client.set_default_fee_bps(&Some(100u32), &contract_id);
|
|
100
112
|
|
|
101
113
|
let res = client.try_fee_view(&7u32, &1_000_000i128);
|
|
102
114
|
assert_eq!(res.err().unwrap().ok().unwrap(), OFTFeeError::InvalidFeeDepositAddress.into());
|
|
@@ -108,29 +120,29 @@ fn test_fee_view_nonzero_fee_errors_when_deposit_address_unset() {
|
|
|
108
120
|
|
|
109
121
|
#[test]
|
|
110
122
|
fn test_set_default_fee_bps_rejects_invalid_value() {
|
|
111
|
-
let TestSetup { client, .. } = setup();
|
|
123
|
+
let TestSetup { client, contract_id, .. } = setup();
|
|
112
124
|
|
|
113
125
|
// Zero is not a valid default fee (use None to remove instead)
|
|
114
|
-
let res = client.try_set_default_fee_bps(&Some(0u32));
|
|
126
|
+
let res = client.try_set_default_fee_bps(&Some(0u32), &contract_id);
|
|
115
127
|
assert_eq!(res.err().unwrap().ok().unwrap(), OFTFeeError::InvalidFeeBps.into());
|
|
116
128
|
|
|
117
129
|
// Exceeds maximum
|
|
118
|
-
let res = client.try_set_default_fee_bps(&Some(10_001u32));
|
|
130
|
+
let res = client.try_set_default_fee_bps(&Some(10_001u32), &contract_id);
|
|
119
131
|
assert_eq!(res.err().unwrap().ok().unwrap(), OFTFeeError::InvalidFeeBps.into());
|
|
120
132
|
}
|
|
121
133
|
|
|
122
134
|
#[test]
|
|
123
135
|
fn test_set_default_fee_bps_rejects_same_value() {
|
|
124
|
-
let TestSetup { client, .. } = setup();
|
|
136
|
+
let TestSetup { client, contract_id, .. } = setup();
|
|
125
137
|
|
|
126
138
|
// None when already None (not set)
|
|
127
139
|
let none: Option<u32> = None;
|
|
128
|
-
let res = client.try_set_default_fee_bps(&none);
|
|
140
|
+
let res = client.try_set_default_fee_bps(&none, &contract_id);
|
|
129
141
|
assert_eq!(res.err().unwrap().ok().unwrap(), OFTFeeError::SameValue.into());
|
|
130
142
|
|
|
131
143
|
// Same value when already set
|
|
132
|
-
client.set_default_fee_bps(&Some(123u32));
|
|
133
|
-
let res2 = client.try_set_default_fee_bps(&Some(123u32));
|
|
144
|
+
client.set_default_fee_bps(&Some(123u32), &contract_id);
|
|
145
|
+
let res2 = client.try_set_default_fee_bps(&Some(123u32), &contract_id);
|
|
134
146
|
assert_eq!(res2.err().unwrap().ok().unwrap(), OFTFeeError::SameValue.into());
|
|
135
147
|
}
|
|
136
148
|
|
|
@@ -140,27 +152,27 @@ fn test_set_default_fee_bps_rejects_same_value() {
|
|
|
140
152
|
|
|
141
153
|
#[test]
|
|
142
154
|
fn test_set_fee_bps_rejects_invalid_and_same_value() {
|
|
143
|
-
let TestSetup { client, .. } = setup();
|
|
155
|
+
let TestSetup { client, contract_id, .. } = setup();
|
|
144
156
|
let dst_eid = 101u32;
|
|
145
157
|
|
|
146
|
-
let res = client.try_set_fee_bps(&dst_eid, &None);
|
|
158
|
+
let res = client.try_set_fee_bps(&dst_eid, &None, &contract_id);
|
|
147
159
|
assert_eq!(res.err().unwrap().ok().unwrap(), OFTFeeError::SameValue.into());
|
|
148
160
|
|
|
149
|
-
let res2 = client.try_set_fee_bps(&dst_eid, &Some(10_001u32));
|
|
161
|
+
let res2 = client.try_set_fee_bps(&dst_eid, &Some(10_001u32), &contract_id);
|
|
150
162
|
assert_eq!(res2.err().unwrap().ok().unwrap(), OFTFeeError::InvalidFeeBps.into());
|
|
151
163
|
}
|
|
152
164
|
|
|
153
165
|
#[test]
|
|
154
166
|
fn test_set_fee_bps_set_and_remove() {
|
|
155
|
-
let TestSetup { client, .. } = setup();
|
|
167
|
+
let TestSetup { client, contract_id, .. } = setup();
|
|
156
168
|
let dst_eid = 101u32;
|
|
157
169
|
|
|
158
|
-
client.set_fee_bps(&dst_eid, &Some(200u32));
|
|
170
|
+
client.set_fee_bps(&dst_eid, &Some(200u32), &contract_id);
|
|
159
171
|
assert_eq!(client.fee_bps(&dst_eid), Some(200u32));
|
|
160
172
|
assert_eq!(client.effective_fee_bps(&dst_eid), 200u32);
|
|
161
173
|
|
|
162
|
-
client.set_default_fee_bps(&Some(111u32));
|
|
163
|
-
client.set_fee_bps(&dst_eid, &None);
|
|
174
|
+
client.set_default_fee_bps(&Some(111u32), &contract_id);
|
|
175
|
+
client.set_fee_bps(&dst_eid, &None, &contract_id);
|
|
164
176
|
assert_eq!(client.fee_bps(&dst_eid), None);
|
|
165
177
|
assert_eq!(client.effective_fee_bps(&dst_eid), 111u32);
|
|
166
178
|
}
|
|
@@ -195,19 +207,19 @@ fn test_charge_fee_errors_without_deposit_address() {
|
|
|
195
207
|
|
|
196
208
|
#[test]
|
|
197
209
|
fn test_set_fee_deposit_address_same_value() {
|
|
198
|
-
let TestSetup { client, fee_deposit, .. } = setup();
|
|
210
|
+
let TestSetup { client, contract_id, fee_deposit, .. } = setup();
|
|
199
211
|
|
|
200
212
|
let fee_deposit_opt = Some(fee_deposit);
|
|
201
|
-
client.set_fee_deposit_address(&fee_deposit_opt);
|
|
202
|
-
let res = client.try_set_fee_deposit_address(&fee_deposit_opt);
|
|
213
|
+
client.set_fee_deposit_address(&fee_deposit_opt, &contract_id);
|
|
214
|
+
let res = client.try_set_fee_deposit_address(&fee_deposit_opt, &contract_id);
|
|
203
215
|
assert_eq!(res.err().unwrap().ok().unwrap(), OFTFeeError::SameValue.into());
|
|
204
216
|
}
|
|
205
217
|
|
|
206
218
|
#[test]
|
|
207
219
|
fn test_charge_fee_zero_amount_no_transfer() {
|
|
208
|
-
let TestSetup { env, client, token, from, fee_deposit, .. } = setup();
|
|
220
|
+
let TestSetup { env, client, contract_id, token, from, fee_deposit, .. } = setup();
|
|
209
221
|
|
|
210
|
-
client.set_fee_deposit_address(&Some(fee_deposit.clone()));
|
|
222
|
+
client.set_fee_deposit_address(&Some(fee_deposit.clone()), &contract_id);
|
|
211
223
|
|
|
212
224
|
let token_client = TokenClient::new(&env, &token);
|
|
213
225
|
let from_before = token_client.balance(&from);
|
|
@@ -222,9 +234,9 @@ fn test_charge_fee_zero_amount_no_transfer() {
|
|
|
222
234
|
|
|
223
235
|
#[test]
|
|
224
236
|
fn test_charge_fee_transfers() {
|
|
225
|
-
let TestSetup { env, client, token, from, fee_deposit, .. } = setup();
|
|
237
|
+
let TestSetup { env, client, contract_id, token, from, fee_deposit, .. } = setup();
|
|
226
238
|
|
|
227
|
-
client.set_fee_deposit_address(&Some(fee_deposit.clone()));
|
|
239
|
+
client.set_fee_deposit_address(&Some(fee_deposit.clone()), &contract_id);
|
|
228
240
|
|
|
229
241
|
let token_client = TokenClient::new(&env, &token);
|
|
230
242
|
let from_before = token_client.balance(&from);
|
|
@@ -238,10 +250,10 @@ fn test_charge_fee_transfers() {
|
|
|
238
250
|
|
|
239
251
|
#[test]
|
|
240
252
|
fn test_fee_view_computes_correct_fee() {
|
|
241
|
-
let TestSetup { client, fee_deposit, .. } = setup();
|
|
253
|
+
let TestSetup { client, contract_id, fee_deposit, .. } = setup();
|
|
242
254
|
|
|
243
|
-
client.set_fee_deposit_address(&Some(fee_deposit));
|
|
244
|
-
client.set_default_fee_bps(&Some(100u32)); // 1%
|
|
255
|
+
client.set_fee_deposit_address(&Some(fee_deposit), &contract_id);
|
|
256
|
+
client.set_default_fee_bps(&Some(100u32), &contract_id); // 1%
|
|
245
257
|
|
|
246
258
|
let fee = client.fee_view(&999u32, &10_000i128);
|
|
247
259
|
assert_eq!(fee, 100); // 1% of 10,000
|