@layerzerolabs/protocol-stellar-v2 0.2.45 → 0.2.47
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 +350 -84
- package/.turbo/turbo-lint.log +243 -72
- package/.turbo/turbo-test.log +1739 -2006
- package/contracts/common-macros/src/lib.rs +17 -1
- package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +3 -3
- package/contracts/oapps/counter/src/tests/mod.rs +2 -2
- package/contracts/oapps/oapp/src/oapp_core.rs +5 -5
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +3 -3
- package/contracts/oapps/oapp/src/tests/mod.rs +3 -3
- package/contracts/oapps/oft/integration-tests/setup.rs +2 -2
- package/contracts/oapps/oft/integration-tests/utils.rs +10 -10
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +7 -7
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +4 -4
- package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +3 -3
- package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +3 -3
- package/contracts/oapps/oft-core/integration-tests/setup.rs +4 -4
- package/contracts/oapps/oft-core/src/oft_core.rs +4 -4
- package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +3 -3
- package/contracts/oapps/oft-core/src/tests/test_utils.rs +4 -4
- package/contracts/workers/dvn/src/tests/dvn.rs +4 -0
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +4 -0
- package/contracts/workers/fee-lib-interfaces/src/dvn_fee_lib.rs +6 -0
- package/contracts/workers/price-feed/src/price_feed.rs +17 -28
- package/package.json +4 -4
- package/sdk/.turbo/turbo-test.log +299 -312
- package/sdk/dist/generated/counter.d.ts +6 -6
- package/sdk/dist/generated/counter.js +6 -6
- package/sdk/dist/generated/dvn_fee_lib.d.ts +8 -3
- package/sdk/dist/generated/dvn_fee_lib.js +5 -3
- package/sdk/dist/generated/oft.d.ts +12 -12
- package/sdk/dist/generated/oft.js +11 -11
- package/sdk/dist/generated/price_feed.d.ts +3 -3
- package/sdk/dist/generated/price_feed.js +3 -3
- package/sdk/package.json +1 -1
- package/sdk/test/counter-sml.test.ts +4 -4
- package/sdk/test/counter-uln.test.ts +4 -4
- package/sdk/test/oft-sml.test.ts +5 -5
|
@@ -244,6 +244,16 @@ pub fn only_auth(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
244
244
|
/// Injects a role check at the start of the function. Panics with
|
|
245
245
|
/// `RbacError::Unauthorized` if the account does not have the role (aligns with OpenZeppelin).
|
|
246
246
|
///
|
|
247
|
+
/// # Security Warning
|
|
248
|
+
///
|
|
249
|
+
/// **IMPORTANT**: This macro checks role membership but does NOT call
|
|
250
|
+
/// `require_auth()`. Use this macro when:
|
|
251
|
+
///
|
|
252
|
+
/// 1. Your function already contains a `require_auth()` call for the account
|
|
253
|
+
/// 2. You need role-based access control without authorization enforcement
|
|
254
|
+
///
|
|
255
|
+
/// If you need both role checking AND authorization, use `#[only_role]` instead.
|
|
256
|
+
///
|
|
247
257
|
/// # Requirements
|
|
248
258
|
/// - The function must have an `Env` parameter
|
|
249
259
|
/// - The function must have a parameter matching the first macro arg (of type `Address` or `&Address`)
|
|
@@ -264,7 +274,7 @@ pub fn only_auth(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
264
274
|
/// ```ignore
|
|
265
275
|
/// pub fn mint(env: Env, caller: Address, amount: i128) {
|
|
266
276
|
/// utils::rbac::ensure_role(&env, &soroban_sdk::Symbol::new(&env, "minter"), &caller);
|
|
267
|
-
/// // Original function body
|
|
277
|
+
/// // Original function body (no require_auth)
|
|
268
278
|
/// }
|
|
269
279
|
/// ```
|
|
270
280
|
#[proc_macro_attribute]
|
|
@@ -277,6 +287,12 @@ pub fn has_role(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
277
287
|
/// Same as `#[has_role]` but also calls `account.require_auth()` to ensure
|
|
278
288
|
/// the caller has authorized the transaction.
|
|
279
289
|
///
|
|
290
|
+
/// **IMPORTANT**: This macro both checks role membership AND enforces
|
|
291
|
+
/// authorization. In Stellar contracts, duplicate `require_auth()` calls for
|
|
292
|
+
/// the same account will cause panics. If your function already contains a
|
|
293
|
+
/// `require_auth()` call for the same account, use `#[has_role]` instead to
|
|
294
|
+
/// avoid duplicate authorization checks.
|
|
295
|
+
///
|
|
280
296
|
/// # Requirements
|
|
281
297
|
/// Same as `#[has_role]`.
|
|
282
298
|
///
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use endpoint_v2::Origin;
|
|
2
|
-
use oapp::oapp_core::
|
|
2
|
+
use oapp::oapp_core::OAPP_MANAGER_ROLE;
|
|
3
3
|
use oapp::oapp_receiver::LzReceiveInternal;
|
|
4
4
|
use oapp_macros::oapp;
|
|
5
5
|
use soroban_sdk::{
|
|
@@ -50,10 +50,10 @@ impl TestOApp {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
/// Grants `
|
|
53
|
+
/// Grants `OAPP_MANAGER_ROLE` to `owner` via the public `grant_role` interface.
|
|
54
54
|
/// Call after `init()` in tests that exercise RBAC-protected entrypoints.
|
|
55
55
|
pub fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
|
|
56
|
-
let role = Symbol::new(env,
|
|
56
|
+
let role = Symbol::new(env, OAPP_MANAGER_ROLE);
|
|
57
57
|
env.mock_auths(&[MockAuth {
|
|
58
58
|
address: owner,
|
|
59
59
|
invoke: &MockAuthInvoke {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use oapp::oapp_core::
|
|
1
|
+
use oapp::oapp_core::OAPP_MANAGER_ROLE;
|
|
2
2
|
use soroban_sdk::{
|
|
3
3
|
testutils::{MockAuth, MockAuthInvoke},
|
|
4
4
|
token::StellarAssetClient,
|
|
@@ -25,7 +25,7 @@ pub fn mint_to(env: &Env, owner: &Address, native_token: &Address, to: &Address,
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
pub fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
|
|
28
|
-
let role = Symbol::new(env,
|
|
28
|
+
let role = Symbol::new(env, OAPP_MANAGER_ROLE);
|
|
29
29
|
env.mock_auths(&[MockAuth {
|
|
30
30
|
address: owner,
|
|
31
31
|
invoke: &MockAuthInvoke {
|
|
@@ -9,7 +9,7 @@ use utils::{
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
/// Role for OApp administrative actions (set_peer, set_delegate, set_enforced_options).
|
|
12
|
-
pub const
|
|
12
|
+
pub const OAPP_MANAGER_ROLE: &str = "OAPP_MANAGER_ROLE";
|
|
13
13
|
|
|
14
14
|
// =====================================================
|
|
15
15
|
// OAppCore Storage and Events
|
|
@@ -73,8 +73,8 @@ pub trait OAppCore: Ownable + RoleBasedAccessControl {
|
|
|
73
73
|
/// # Arguments
|
|
74
74
|
/// * `eid` - The endpoint ID
|
|
75
75
|
/// * `peer` - The address of the peer to be associated with the corresponding endpoint, or None to remove the peer
|
|
76
|
-
/// * `operator` - The address that must have
|
|
77
|
-
#[only_role(operator,
|
|
76
|
+
/// * `operator` - The address that must have OAPP_MANAGER_ROLE
|
|
77
|
+
#[only_role(operator, OAPP_MANAGER_ROLE)]
|
|
78
78
|
fn set_peer(
|
|
79
79
|
env: &soroban_sdk::Env,
|
|
80
80
|
eid: u32,
|
|
@@ -89,8 +89,8 @@ pub trait OAppCore: Ownable + RoleBasedAccessControl {
|
|
|
89
89
|
///
|
|
90
90
|
/// # Arguments
|
|
91
91
|
/// * `delegate` - The address of the delegate to be set, or None to remove the delegate
|
|
92
|
-
/// * `operator` - The address that must have
|
|
93
|
-
#[only_role(operator,
|
|
92
|
+
/// * `operator` - The address that must have OAPP_MANAGER_ROLE
|
|
93
|
+
#[only_role(operator, OAPP_MANAGER_ROLE)]
|
|
94
94
|
fn set_delegate(env: &soroban_sdk::Env, delegate: &Option<soroban_sdk::Address>, operator: &soroban_sdk::Address) {
|
|
95
95
|
endpoint_client::<Self>(env).set_delegate(&env.current_contract_address(), delegate);
|
|
96
96
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use crate::{self as oapp, errors::OAppError, oapp_core::
|
|
1
|
+
use crate::{self as oapp, errors::OAppError, oapp_core::OAPP_MANAGER_ROLE};
|
|
2
2
|
use common_macros::{contract_trait, only_role, storage};
|
|
3
3
|
use soroban_sdk::{assert_with_error, contractevent, contracttype, panic_with_error, Bytes, Env, Vec};
|
|
4
4
|
use utils::{buffer_reader::BufferReader, rbac::RoleBasedAccessControl};
|
|
@@ -53,8 +53,8 @@ pub trait OAppOptionsType3: RoleBasedAccessControl {
|
|
|
53
53
|
///
|
|
54
54
|
/// # Arguments
|
|
55
55
|
/// * `options` - A vector of EnforcedOptionParam structures specifying enforced options
|
|
56
|
-
/// * `operator` - The address that must have
|
|
57
|
-
#[only_role(operator,
|
|
56
|
+
/// * `operator` - The address that must have OAPP_MANAGER_ROLE
|
|
57
|
+
#[only_role(operator, OAPP_MANAGER_ROLE)]
|
|
58
58
|
fn set_enforced_options(
|
|
59
59
|
env: &soroban_sdk::Env,
|
|
60
60
|
options: &soroban_sdk::Vec<oapp::oapp_options_type3::EnforcedOptionParam>,
|
|
@@ -4,15 +4,15 @@ mod oapp_receiver;
|
|
|
4
4
|
mod oapp_sender;
|
|
5
5
|
mod test_macros;
|
|
6
6
|
|
|
7
|
-
use crate::oapp_core::
|
|
7
|
+
use crate::oapp_core::OAPP_MANAGER_ROLE;
|
|
8
8
|
use soroban_sdk::{
|
|
9
9
|
testutils::{MockAuth, MockAuthInvoke},
|
|
10
10
|
Address, Env, IntoVal, Symbol,
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
/// Grants `
|
|
13
|
+
/// Grants `OAPP_MANAGER_ROLE` to `owner` via the public `grant_role` interface.
|
|
14
14
|
pub(super) fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
|
|
15
|
-
let role = Symbol::new(env,
|
|
15
|
+
let role = Symbol::new(env, OAPP_MANAGER_ROLE);
|
|
16
16
|
env.mock_auths(&[MockAuth {
|
|
17
17
|
address: owner,
|
|
18
18
|
invoke: &MockAuthInvoke {
|
|
@@ -10,7 +10,7 @@ use crate::{
|
|
|
10
10
|
oft_types::OftType,
|
|
11
11
|
};
|
|
12
12
|
use endpoint_v2::{EndpointV2, EndpointV2Client};
|
|
13
|
-
use oapp::oapp_core::
|
|
13
|
+
use oapp::oapp_core::OAPP_MANAGER_ROLE;
|
|
14
14
|
use simple_message_lib::{SimpleMessageLib, SimpleMessageLibClient};
|
|
15
15
|
use soroban_sdk::{
|
|
16
16
|
contract, contractimpl, contracttype, log,
|
|
@@ -215,7 +215,7 @@ pub fn wire_oft(env: &Env, chains: &[&ChainSetup<'_>]) {
|
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
|
|
218
|
-
let role = Symbol::new(env,
|
|
218
|
+
let role = Symbol::new(env, OAPP_MANAGER_ROLE);
|
|
219
219
|
env.mock_auths(&[MockAuth {
|
|
220
220
|
address: owner,
|
|
221
221
|
invoke: &MockAuthInvoke {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//! Utility functions for OFT-STD integration tests.
|
|
2
2
|
|
|
3
|
-
use crate::extensions::rate_limiter::{Direction, Mode, RateLimitConfig,
|
|
4
|
-
use crate::extensions::oft_fee::
|
|
3
|
+
use crate::extensions::rate_limiter::{Direction, Mode, RateLimitConfig, RATE_LIMITER_MANAGER_ROLE};
|
|
4
|
+
use crate::extensions::oft_fee::FEE_MANAGER_ROLE;
|
|
5
5
|
use crate::extensions::pausable::{PAUSER_ROLE, UNPAUSER_ROLE};
|
|
6
6
|
use crate::integration_tests::setup::{decode_packet, ChainSetup};
|
|
7
7
|
use crate::MintableClient;
|
|
@@ -406,8 +406,8 @@ pub fn is_paused(chain: &ChainSetup<'_>) -> bool {
|
|
|
406
406
|
// ============================================================================
|
|
407
407
|
|
|
408
408
|
pub fn set_fee_deposit_address(env: &Env, chain: &ChainSetup<'_>, deposit_address: &Address) {
|
|
409
|
-
// `set_fee_deposit_address` is protected by RBAC (`
|
|
410
|
-
let role = Symbol::new(env,
|
|
409
|
+
// `set_fee_deposit_address` is protected by RBAC (`FEE_MANAGER_ROLE`). Grant it to owner for tests.
|
|
410
|
+
let role = Symbol::new(env, FEE_MANAGER_ROLE);
|
|
411
411
|
env.mock_auths(&[MockAuth {
|
|
412
412
|
address: &chain.owner,
|
|
413
413
|
invoke: &MockAuthInvoke {
|
|
@@ -433,8 +433,8 @@ pub fn set_fee_deposit_address(env: &Env, chain: &ChainSetup<'_>, deposit_addres
|
|
|
433
433
|
}
|
|
434
434
|
|
|
435
435
|
pub fn set_default_fee_bps(env: &Env, chain: &ChainSetup<'_>, fee_bps: u32) {
|
|
436
|
-
// `set_default_fee_bps` is protected by RBAC (`
|
|
437
|
-
let role = Symbol::new(env,
|
|
436
|
+
// `set_default_fee_bps` is protected by RBAC (`FEE_MANAGER_ROLE`). Grant it to owner for tests.
|
|
437
|
+
let role = Symbol::new(env, FEE_MANAGER_ROLE);
|
|
438
438
|
env.mock_auths(&[MockAuth {
|
|
439
439
|
address: &chain.owner,
|
|
440
440
|
invoke: &MockAuthInvoke {
|
|
@@ -460,8 +460,8 @@ pub fn set_default_fee_bps(env: &Env, chain: &ChainSetup<'_>, fee_bps: u32) {
|
|
|
460
460
|
}
|
|
461
461
|
|
|
462
462
|
pub fn set_fee_bps(env: &Env, chain: &ChainSetup<'_>, dst_eid: u32, fee_bps: u32) {
|
|
463
|
-
// `set_fee_bps` is protected by RBAC (`
|
|
464
|
-
let role = Symbol::new(env,
|
|
463
|
+
// `set_fee_bps` is protected by RBAC (`FEE_MANAGER_ROLE`). Grant it to owner for tests.
|
|
464
|
+
let role = Symbol::new(env, FEE_MANAGER_ROLE);
|
|
465
465
|
env.mock_auths(&[MockAuth {
|
|
466
466
|
address: &chain.owner,
|
|
467
467
|
invoke: &MockAuthInvoke {
|
|
@@ -510,8 +510,8 @@ pub fn set_rate_limit_with_mode(
|
|
|
510
510
|
window_seconds: u64,
|
|
511
511
|
mode: Mode,
|
|
512
512
|
) {
|
|
513
|
-
// `set_rate_limit` is protected by RBAC (`
|
|
514
|
-
let role = Symbol::new(env,
|
|
513
|
+
// `set_rate_limit` is protected by RBAC (`RATE_LIMITER_MANAGER_ROLE`). Grant it to owner for tests.
|
|
514
|
+
let role = Symbol::new(env, RATE_LIMITER_MANAGER_ROLE);
|
|
515
515
|
env.mock_auths(&[MockAuth {
|
|
516
516
|
address: &chain.owner,
|
|
517
517
|
invoke: &MockAuthInvoke {
|
|
@@ -3,7 +3,7 @@ use soroban_sdk::{assert_with_error, contractevent, token::TokenClient, Address,
|
|
|
3
3
|
use utils::{option_ext::OptionExt, rbac::RoleBasedAccessControl};
|
|
4
4
|
|
|
5
5
|
/// Role for fee configuration (set_default_fee_bps, set_fee_bps, set_fee_deposit_address).
|
|
6
|
-
pub const
|
|
6
|
+
pub const FEE_MANAGER_ROLE: &str = "FEE_MANAGER_ROLE";
|
|
7
7
|
|
|
8
8
|
/// Base fee in basis points (10,000 BPS = 100%)
|
|
9
9
|
/// Used as denominator in fee calculations
|
|
@@ -82,8 +82,8 @@ pub trait OFTFee: OFTFeeInternal + RoleBasedAccessControl {
|
|
|
82
82
|
/// - `Some(n)`: sets the default fee to `n` basis points (must be >0 and <=10,000).
|
|
83
83
|
/// - `Some(0)`: rejected — use `None` to remove the default fee instead.
|
|
84
84
|
/// - `None`: removes the default fee (effective rate becomes 0).
|
|
85
|
-
/// * `operator` - The address that must have
|
|
86
|
-
#[only_role(operator,
|
|
85
|
+
/// * `operator` - The address that must have FEE_MANAGER_ROLE
|
|
86
|
+
#[only_role(operator, FEE_MANAGER_ROLE)]
|
|
87
87
|
fn set_default_fee_bps(env: &soroban_sdk::Env, default_fee_bps: &Option<u32>, operator: &soroban_sdk::Address) {
|
|
88
88
|
Self::__set_default_fee_bps(env, default_fee_bps);
|
|
89
89
|
}
|
|
@@ -96,8 +96,8 @@ pub trait OFTFee: OFTFeeInternal + RoleBasedAccessControl {
|
|
|
96
96
|
/// # Arguments
|
|
97
97
|
/// * `dst_eid` - The destination endpoint ID
|
|
98
98
|
/// * `fee_bps` - The fee rate (0-10,000), or None to remove the fee configuration
|
|
99
|
-
/// * `operator` - The address that must have
|
|
100
|
-
#[only_role(operator,
|
|
99
|
+
/// * `operator` - The address that must have FEE_MANAGER_ROLE
|
|
100
|
+
#[only_role(operator, FEE_MANAGER_ROLE)]
|
|
101
101
|
fn set_fee_bps(env: &soroban_sdk::Env, dst_eid: u32, fee_bps: &Option<u32>, operator: &soroban_sdk::Address) {
|
|
102
102
|
Self::__set_fee_bps(env, dst_eid, fee_bps);
|
|
103
103
|
}
|
|
@@ -106,8 +106,8 @@ pub trait OFTFee: OFTFeeInternal + RoleBasedAccessControl {
|
|
|
106
106
|
///
|
|
107
107
|
/// # Arguments
|
|
108
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
|
|
110
|
-
#[only_role(operator,
|
|
109
|
+
/// * `operator` - The address that must have FEE_MANAGER_ROLE
|
|
110
|
+
#[only_role(operator, FEE_MANAGER_ROLE)]
|
|
111
111
|
fn set_fee_deposit_address(
|
|
112
112
|
env: &soroban_sdk::Env,
|
|
113
113
|
fee_deposit_address: &Option<soroban_sdk::Address>,
|
|
@@ -4,7 +4,7 @@ use soroban_sdk::{assert_with_error, contractevent, contracttype, Env};
|
|
|
4
4
|
use utils::rbac::RoleBasedAccessControl;
|
|
5
5
|
|
|
6
6
|
/// Role for rate limiter configuration (set_rate_limit).
|
|
7
|
-
pub const
|
|
7
|
+
pub const RATE_LIMITER_MANAGER_ROLE: &str = "RATE_LIMITER_MANAGER_ROLE";
|
|
8
8
|
|
|
9
9
|
// =========================================================================
|
|
10
10
|
// Types
|
|
@@ -108,8 +108,8 @@ pub trait RateLimiter: RateLimiterInternal + RoleBasedAccessControl {
|
|
|
108
108
|
/// * `direction` - The direction (Inbound or Outbound)
|
|
109
109
|
/// * `eid` - The endpoint ID
|
|
110
110
|
/// * `config` - The rate limit configuration, or None to remove the rate limit
|
|
111
|
-
/// * `operator` - The address that must have
|
|
112
|
-
#[only_role(operator,
|
|
111
|
+
/// * `operator` - The address that must have RATE_LIMITER_MANAGER_ROLE
|
|
112
|
+
#[only_role(operator, RATE_LIMITER_MANAGER_ROLE)]
|
|
113
113
|
fn set_rate_limit(
|
|
114
114
|
env: &soroban_sdk::Env,
|
|
115
115
|
direction: &oft::rate_limiter::Direction,
|
|
@@ -279,7 +279,7 @@ fn calculate_decayed_in_flight(env: &Env, state: &RateLimitState) -> i128 {
|
|
|
279
279
|
assert_with_error!(env, timestamp >= state.last_update, RateLimitError::InvalidTimestamp);
|
|
280
280
|
|
|
281
281
|
let elapsed = timestamp - state.last_update;
|
|
282
|
-
let decay = (elapsed as i128)
|
|
282
|
+
let decay = (elapsed as i128).saturating_mul(state.config.limit) / (state.config.window_seconds as i128);
|
|
283
283
|
|
|
284
284
|
// Ensure the decayed in-flight amount is not negative
|
|
285
285
|
(state.in_flight_on_last_update - decay).max(0)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
extern crate std;
|
|
2
2
|
|
|
3
3
|
use crate::extensions::oft_fee::{OFTFee, OFTFeeError, OFTFeeInternal};
|
|
4
|
-
use crate::extensions::oft_fee::
|
|
4
|
+
use crate::extensions::oft_fee::FEE_MANAGER_ROLE;
|
|
5
5
|
use soroban_sdk::{
|
|
6
6
|
contract, contractimpl,
|
|
7
7
|
testutils::{Address as _, MockAuth, MockAuthInvoke},
|
|
@@ -34,10 +34,10 @@ impl RoleBasedAccessControl for FeeTestContract {}
|
|
|
34
34
|
|
|
35
35
|
#[contractimpl]
|
|
36
36
|
impl FeeTestContract {
|
|
37
|
-
/// Test-only: grants
|
|
37
|
+
/// Test-only: grants FEE_MANAGER_ROLE to the contract.
|
|
38
38
|
pub fn init_roles(env: Env) {
|
|
39
39
|
let contract_id = env.current_contract_address();
|
|
40
|
-
grant_role_no_auth(&env, &contract_id, &Symbol::new(&env,
|
|
40
|
+
grant_role_no_auth(&env, &contract_id, &Symbol::new(&env, FEE_MANAGER_ROLE), &contract_id);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
pub fn fee_view(env: Env, dst_eid: u32, amount_ld: i128) -> i128 {
|
|
@@ -4,7 +4,7 @@ use crate as oft;
|
|
|
4
4
|
use crate::extensions::rate_limiter::{
|
|
5
5
|
Direction, Mode, RateLimitConfig, RateLimitError, RateLimiter, RateLimiterInternal,
|
|
6
6
|
};
|
|
7
|
-
use crate::extensions::rate_limiter::
|
|
7
|
+
use crate::extensions::rate_limiter::RATE_LIMITER_MANAGER_ROLE;
|
|
8
8
|
use soroban_sdk::{contract, contractimpl, testutils::Ledger as _, Address, Env, Symbol};
|
|
9
9
|
use utils::auth::Auth;
|
|
10
10
|
use utils::rbac::{grant_role_no_auth, RoleBasedAccessControl};
|
|
@@ -32,13 +32,13 @@ impl RoleBasedAccessControl for RateLimiterTestContract {}
|
|
|
32
32
|
|
|
33
33
|
#[contractimpl]
|
|
34
34
|
impl RateLimiterTestContract {
|
|
35
|
-
/// Test-only: grants
|
|
35
|
+
/// Test-only: grants RATE_LIMITER_MANAGER_ROLE to the contract.
|
|
36
36
|
pub fn init_roles(env: Env) {
|
|
37
37
|
let contract_id = env.current_contract_address();
|
|
38
38
|
grant_role_no_auth(
|
|
39
39
|
&env,
|
|
40
40
|
&contract_id,
|
|
41
|
-
&Symbol::new(&env,
|
|
41
|
+
&Symbol::new(&env, RATE_LIMITER_MANAGER_ROLE),
|
|
42
42
|
&contract_id,
|
|
43
43
|
);
|
|
44
44
|
}
|
|
@@ -20,7 +20,7 @@ use soroban_sdk::{
|
|
|
20
20
|
token::{StellarAssetClient, TokenClient},
|
|
21
21
|
Address, Bytes, BytesN, Env, IntoVal, Symbol,
|
|
22
22
|
};
|
|
23
|
-
use oapp::oapp_core::
|
|
23
|
+
use oapp::oapp_core::OAPP_MANAGER_ROLE;
|
|
24
24
|
use utils::rbac::grant_role_no_auth;
|
|
25
25
|
|
|
26
26
|
// ============================================================================
|
|
@@ -182,9 +182,9 @@ fn setup_chain<'a>(env: &Env) -> ChainSetup<'a> {
|
|
|
182
182
|
let shared_decimals: u32 = 6; // Default shared decimals
|
|
183
183
|
let oft_address = env.register(TestOFT, (&oft_token, &owner, &endpoint_address, &delegate, &shared_decimals));
|
|
184
184
|
|
|
185
|
-
// Grant
|
|
185
|
+
// Grant OAPP_MANAGER_ROLE to owner so they can call set_peer, set_delegate, set_msg_inspector, etc.
|
|
186
186
|
env.as_contract(&oft_address, || {
|
|
187
|
-
grant_role_no_auth(env, &owner, &Symbol::new(env,
|
|
187
|
+
grant_role_no_auth(env, &owner, &Symbol::new(env, OAPP_MANAGER_ROLE), &owner);
|
|
188
188
|
});
|
|
189
189
|
let composer_address = env.register(DummyComposer, (&endpoint_address,));
|
|
190
190
|
|
|
@@ -264,7 +264,7 @@ pub fn wire_oft(env: &Env, chains: &[&ChainSetup<'_>]) {
|
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
|
|
267
|
-
let role = soroban_sdk::Symbol::new(env, oapp::oapp_core::
|
|
267
|
+
let role = soroban_sdk::Symbol::new(env, oapp::oapp_core::OAPP_MANAGER_ROLE);
|
|
268
268
|
env.mock_auths(&[MockAuth {
|
|
269
269
|
address: owner,
|
|
270
270
|
invoke: &MockAuthInvoke {
|
|
@@ -58,7 +58,7 @@ use crate::{
|
|
|
58
58
|
use common_macros::{contract_trait, only_role};
|
|
59
59
|
use endpoint_v2::{MessagingComposerClient, MessagingFee, MessagingReceipt};
|
|
60
60
|
use oapp::{
|
|
61
|
-
oapp_core::{init_ownable_oapp,
|
|
61
|
+
oapp_core::{init_ownable_oapp, OAPP_MANAGER_ROLE},
|
|
62
62
|
oapp_options_type3::OAppOptionsType3,
|
|
63
63
|
oapp_receiver::OAppReceiver,
|
|
64
64
|
oapp_sender::{FeePayer, OAppSenderInternal},
|
|
@@ -448,12 +448,12 @@ pub trait OFTCore: OFTInternal {
|
|
|
448
448
|
/// Pass `None` to remove the inspector and disable outbound validation.
|
|
449
449
|
///
|
|
450
450
|
/// # Authorization
|
|
451
|
-
/// Requires the caller to have `
|
|
451
|
+
/// Requires the caller to have `OAPP_MANAGER_ROLE`.
|
|
452
452
|
///
|
|
453
453
|
/// # Arguments
|
|
454
454
|
/// * `inspector` - Address of the inspector contract, or `None` to remove it
|
|
455
|
-
/// * `operator` - The address that must have
|
|
456
|
-
#[only_role(operator,
|
|
455
|
+
/// * `operator` - The address that must have OAPP_MANAGER_ROLE
|
|
456
|
+
#[only_role(operator, OAPP_MANAGER_ROLE)]
|
|
457
457
|
fn set_msg_inspector(
|
|
458
458
|
env: &soroban_sdk::Env,
|
|
459
459
|
inspector: &Option<soroban_sdk::Address>,
|
|
@@ -60,7 +60,7 @@ fn test_set_msg_inspector() {
|
|
|
60
60
|
// Deploy a passing inspector
|
|
61
61
|
let inspector_address = env.register(PassingInspector, ());
|
|
62
62
|
|
|
63
|
-
// Owner (with
|
|
63
|
+
// Owner (with OAPP_MANAGER_ROLE) sets the inspector
|
|
64
64
|
env.mock_auths(&[MockAuth {
|
|
65
65
|
address: &setup.owner,
|
|
66
66
|
invoke: &MockAuthInvoke {
|
|
@@ -127,7 +127,7 @@ fn test_set_msg_inspector_requires_owner() {
|
|
|
127
127
|
// Deploy a passing inspector
|
|
128
128
|
let inspector_address = env.register(PassingInspector, ());
|
|
129
129
|
|
|
130
|
-
// Non-owner (without
|
|
130
|
+
// Non-owner (without OAPP_MANAGER_ROLE) tries to set the inspector
|
|
131
131
|
let non_owner = Address::generate(&env);
|
|
132
132
|
env.mock_auths(&[MockAuth {
|
|
133
133
|
address: &non_owner,
|
|
@@ -139,7 +139,7 @@ fn test_set_msg_inspector_requires_owner() {
|
|
|
139
139
|
},
|
|
140
140
|
}]);
|
|
141
141
|
|
|
142
|
-
// This should panic because non_owner does not have
|
|
142
|
+
// This should panic because non_owner does not have OAPP_MANAGER_ROLE
|
|
143
143
|
setup.oft.set_msg_inspector(&Some(inspector_address), &non_owner);
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -8,7 +8,7 @@ use crate::{
|
|
|
8
8
|
types::{OFTReceipt, SendParam},
|
|
9
9
|
};
|
|
10
10
|
use endpoint_v2::{LayerZeroReceiverClient, MessagingFee, MessagingParams, MessagingReceipt, Origin};
|
|
11
|
-
use oapp::oapp_core::{OAppCoreClient,
|
|
11
|
+
use oapp::oapp_core::{OAppCoreClient, OAPP_MANAGER_ROLE};
|
|
12
12
|
use soroban_sdk::{
|
|
13
13
|
address_payload::AddressPayload,
|
|
14
14
|
bytes, contract, contractimpl, log, symbol_short,
|
|
@@ -101,7 +101,7 @@ pub fn create_origin(src_eid: u32, sender: &BytesN<32>, nonce: u64) -> Origin {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
|
|
104
|
-
let role = Symbol::new(env, oapp::oapp_core::
|
|
104
|
+
let role = Symbol::new(env, oapp::oapp_core::OAPP_MANAGER_ROLE);
|
|
105
105
|
env.mock_auths(&[MockAuth {
|
|
106
106
|
address: owner,
|
|
107
107
|
invoke: &MockAuthInvoke {
|
|
@@ -613,12 +613,12 @@ impl<'a> OFTTestSetupBuilder<'a> {
|
|
|
613
613
|
OFTTestSetup::mint_to(env, &owner, &native_token, &owner, INITIAL_MINT_AMOUNT);
|
|
614
614
|
OFTTestSetup::mint_to(env, &owner, &zro_token, &owner, INITIAL_MINT_AMOUNT);
|
|
615
615
|
|
|
616
|
-
// Grant
|
|
616
|
+
// Grant OAPP_MANAGER_ROLE to owner so they can call set_peer, set_delegate, set_msg_inspector, etc.
|
|
617
617
|
env.as_contract(&oft_address, || {
|
|
618
618
|
grant_role_no_auth(
|
|
619
619
|
env,
|
|
620
620
|
&owner,
|
|
621
|
-
&Symbol::new(env,
|
|
621
|
+
&Symbol::new(env, OAPP_MANAGER_ROLE),
|
|
622
622
|
&owner,
|
|
623
623
|
);
|
|
624
624
|
});
|
|
@@ -73,4 +73,10 @@ pub trait IDvnFeeLib {
|
|
|
73
73
|
/// # Returns
|
|
74
74
|
/// The calculated fee in native token units (stroops for Stellar).
|
|
75
75
|
fn get_fee(env: &Env, dvn: &Address, params: &DvnFeeParams) -> i128;
|
|
76
|
+
|
|
77
|
+
/// Returns the fee library contract version.
|
|
78
|
+
///
|
|
79
|
+
/// # Returns
|
|
80
|
+
/// Tuple of (major version, minor version).
|
|
81
|
+
fn version(env: &Env) -> (u64, u32);
|
|
76
82
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
use common_macros::{contract_impl, lz_contract, only_auth};
|
|
2
2
|
use fee_lib_interfaces::{FeeEstimate, ILayerZeroPriceFeed, Price};
|
|
3
|
-
use soroban_sdk::{assert_with_error,
|
|
3
|
+
use soroban_sdk::{assert_with_error, Address, Env, Vec};
|
|
4
|
+
use utils::option_ext::OptionExt;
|
|
4
5
|
|
|
5
6
|
use crate::{
|
|
6
7
|
errors::PriceFeedError,
|
|
@@ -110,7 +111,7 @@ impl LzPriceFeed {
|
|
|
110
111
|
|
|
111
112
|
/// Set prices for multiple destinations (price updater or owner)
|
|
112
113
|
pub fn set_price(env: &Env, price_updater: &Address, prices: &Vec<UpdatePrice>) {
|
|
113
|
-
Self::
|
|
114
|
+
Self::require_owner_or_price_updater(env, price_updater);
|
|
114
115
|
|
|
115
116
|
prices.iter().for_each(|update| Self::set_price_internal(env, update.eid, &update.price));
|
|
116
117
|
}
|
|
@@ -118,7 +119,7 @@ impl LzPriceFeed {
|
|
|
118
119
|
/// Set price for Arbitrum with extension (price updater or owner)
|
|
119
120
|
/// Corresponds to setPriceForArbitrum in PriceFeed.sol
|
|
120
121
|
pub fn set_price_for_arbitrum(env: &Env, price_updater: &Address, update: &UpdatePriceExt) {
|
|
121
|
-
Self::
|
|
122
|
+
Self::require_owner_or_price_updater(env, price_updater);
|
|
122
123
|
|
|
123
124
|
Self::set_price_internal(env, update.eid, &update.price);
|
|
124
125
|
|
|
@@ -131,7 +132,7 @@ impl LzPriceFeed {
|
|
|
131
132
|
///
|
|
132
133
|
/// Kept as a standalone contract function (not part of the canonical `fee_lib_interfaces::ILayerZeroPriceFeed` interface).
|
|
133
134
|
pub fn set_native_token_price_usd(env: &Env, price_updater: &Address, native_token_price_usd: u128) {
|
|
134
|
-
Self::
|
|
135
|
+
Self::require_owner_or_price_updater(env, price_updater);
|
|
135
136
|
PriceFeedStorage::set_native_price_usd(env, &native_token_price_usd);
|
|
136
137
|
}
|
|
137
138
|
|
|
@@ -171,7 +172,7 @@ impl LzPriceFeed {
|
|
|
171
172
|
|
|
172
173
|
/// Estimate fee with default model
|
|
173
174
|
fn estimate_fee_with_default_model(env: &Env, dst_eid: u32, calldata_size: u32, gas: u128) -> (u128, u128) {
|
|
174
|
-
let price = Self::get_price(env, dst_eid).
|
|
175
|
+
let price = Self::get_price(env, dst_eid).unwrap_or_panic(env, PriceFeedError::NoPrice);
|
|
175
176
|
|
|
176
177
|
// assuming the _gas includes (1) the 21,000 overhead and (2) not the calldata gas
|
|
177
178
|
let gas_for_calldata = (calldata_size as u128) * (price.gas_per_byte as u128);
|
|
@@ -183,17 +184,14 @@ impl LzPriceFeed {
|
|
|
183
184
|
|
|
184
185
|
/// Estimate fee with Optimism model
|
|
185
186
|
fn estimate_fee_with_optimism_model(env: &Env, dst_eid: u32, calldata_size: u32, gas: u128) -> (u128, u128) {
|
|
186
|
-
let ethereum_id = Self::get_l1_lookup_id_for_optimism_model(env, dst_eid);
|
|
187
|
-
|
|
188
187
|
// L1 fee (Ethereum)
|
|
189
|
-
let
|
|
190
|
-
|
|
188
|
+
let ethereum_id = Self::get_l1_lookup_id_for_optimism_model(env, dst_eid);
|
|
189
|
+
let ethereum_price = Self::get_price(env, ethereum_id).unwrap_or_panic(env, PriceFeedError::NoPrice);
|
|
191
190
|
let gas_for_l1_calldata = ((calldata_size as u128) * (ethereum_price.gas_per_byte as u128)) + 3188; // 2100 + 68 * 16
|
|
192
191
|
let l1_fee = gas_for_l1_calldata * (ethereum_price.gas_price_in_unit as u128);
|
|
193
192
|
|
|
194
193
|
// L2 fee (Optimism)
|
|
195
|
-
let optimism_price =
|
|
196
|
-
Self::get_price(env, dst_eid).unwrap_or_else(|| panic_with_error!(env, PriceFeedError::NoPrice));
|
|
194
|
+
let optimism_price = Self::get_price(env, dst_eid).unwrap_or_panic(env, PriceFeedError::NoPrice);
|
|
197
195
|
let gas_for_l2_calldata = (calldata_size as u128) * (optimism_price.gas_per_byte as u128);
|
|
198
196
|
let l2_fee = (gas_for_l2_calldata + gas) * (optimism_price.gas_price_in_unit as u128);
|
|
199
197
|
|
|
@@ -207,16 +205,13 @@ impl LzPriceFeed {
|
|
|
207
205
|
|
|
208
206
|
/// Estimate fee with Arbitrum model
|
|
209
207
|
fn estimate_fee_with_arbitrum_model(env: &Env, dst_eid: u32, calldata_size: u32, gas: u128) -> (u128, u128) {
|
|
210
|
-
let arbitrum_price =
|
|
211
|
-
Self::get_price(env, dst_eid).unwrap_or_else(|| panic_with_error!(env, PriceFeedError::NoPrice));
|
|
212
|
-
|
|
213
|
-
let arbitrum_price_ext = Self::arbitrum_price_ext(env);
|
|
214
|
-
|
|
215
208
|
// L1 fee (compressed calldata)
|
|
209
|
+
let arbitrum_price_ext = Self::arbitrum_price_ext(env);
|
|
216
210
|
let gas_for_l1_calldata = (((calldata_size as u128) * Self::arbitrum_compression_percent(env)) / 100)
|
|
217
211
|
* (arbitrum_price_ext.gas_per_l1_calldata_byte as u128);
|
|
218
212
|
|
|
219
213
|
// L2 fee
|
|
214
|
+
let arbitrum_price = Self::get_price(env, dst_eid).unwrap_or_panic(env, PriceFeedError::NoPrice);
|
|
220
215
|
let gas_for_l2_calldata = (calldata_size as u128) * (arbitrum_price.gas_per_byte as u128);
|
|
221
216
|
let gas_fee = (gas + (arbitrum_price_ext.gas_per_l2_tx as u128) + gas_for_l1_calldata + gas_for_l2_calldata)
|
|
222
217
|
* (arbitrum_price.gas_price_in_unit as u128);
|
|
@@ -251,18 +246,12 @@ impl LzPriceFeed {
|
|
|
251
246
|
}
|
|
252
247
|
|
|
253
248
|
/// Check if caller is price updater or owner
|
|
254
|
-
fn
|
|
249
|
+
fn require_owner_or_price_updater(env: &Env, caller: &Address) {
|
|
255
250
|
caller.require_auth();
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Check if caller is an active price updater
|
|
265
|
-
assert_with_error!(env, Self::is_price_updater(env, caller), PriceFeedError::OnlyPriceUpdater);
|
|
251
|
+
assert_with_error!(
|
|
252
|
+
env,
|
|
253
|
+
Self::owner(env).as_ref() == Some(caller) || Self::is_price_updater(env, caller),
|
|
254
|
+
PriceFeedError::OnlyPriceUpdater
|
|
255
|
+
);
|
|
266
256
|
}
|
|
267
257
|
}
|
|
268
|
-
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layerzerolabs/protocol-stellar-v2",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.47",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "LZBL-1.2",
|
|
6
6
|
"devDependencies": {
|
|
7
7
|
"@types/node": "^22.18.6",
|
|
8
8
|
"tsx": "^4.19.3",
|
|
9
9
|
"typescript": "^5.8.2",
|
|
10
|
-
"@layerzerolabs/common-node-utils": "0.2.
|
|
11
|
-
"@layerzerolabs/
|
|
12
|
-
"@layerzerolabs/
|
|
10
|
+
"@layerzerolabs/common-node-utils": "0.2.47",
|
|
11
|
+
"@layerzerolabs/stellar-ts-bindings-gen": "0.2.47",
|
|
12
|
+
"@layerzerolabs/vm-tooling-stellar": "0.2.47"
|
|
13
13
|
},
|
|
14
14
|
"publishConfig": {
|
|
15
15
|
"access": "restricted",
|