@layerzerolabs/protocol-stellar-v2 0.2.19 → 0.2.21
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 +795 -791
- package/.turbo/turbo-lint.log +325 -155
- package/.turbo/turbo-test.log +1398 -1277
- package/Cargo.lock +122 -111
- package/Cargo.toml +32 -16
- package/contracts/common-macros/Cargo.toml +7 -7
- package/contracts/common-macros/src/auth.rs +18 -37
- package/contracts/common-macros/src/contract_ttl.rs +18 -7
- package/contracts/common-macros/src/lib.rs +31 -14
- package/contracts/common-macros/src/lz_contract.rs +38 -7
- package/contracts/common-macros/src/storage.rs +251 -292
- package/contracts/common-macros/src/tests/contract_ttl.rs +1 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +6 -12
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +12 -17
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +2 -7
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +20 -14
- package/contracts/common-macros/src/tests/upgradeable.rs +26 -4
- package/contracts/common-macros/src/ttl_configurable.rs +2 -10
- package/contracts/common-macros/src/ttl_extendable.rs +2 -10
- package/contracts/common-macros/src/upgradeable.rs +61 -26
- package/contracts/common-macros/src/utils.rs +0 -9
- package/contracts/endpoint-v2/src/lib.rs +3 -2
- package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +2 -2
- package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +3 -3
- package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +4 -4
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +17 -5
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
- package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +2 -2
- package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +2 -2
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +6 -6
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +67 -37
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +5 -5
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +44 -54
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +7 -7
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +8 -8
- package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +4 -4
- package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +2 -2
- package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +2 -2
- package/contracts/layerzero-views/Cargo.toml +0 -1
- package/contracts/layerzero-views/src/layerzero_view.rs +1 -13
- package/contracts/macro-integration-tests/Cargo.toml +5 -15
- package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +48 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +170 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +154 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +338 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +435 -0
- package/contracts/macro-integration-tests/tests/runtime.rs +1 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.stderr +71 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.rs +10 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +38 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +96 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/minimal_contract.rs +64 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/struct_with_fields.rs +46 -0
- package/contracts/macro-integration-tests/tests/ui/ownable/fail/only_auth_missing_env.stderr +8 -0
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/only_auth_env_param_variants.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui_oapp.rs +11 -0
- package/contracts/message-libs/message-lib-common/Cargo.toml +0 -1
- package/contracts/message-libs/message-lib-common/src/errors.rs +1 -1
- package/contracts/message-libs/treasury/Cargo.toml +0 -2
- package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +2 -2
- package/contracts/message-libs/uln-302/src/events.rs +4 -0
- package/contracts/message-libs/uln-302/src/send_uln.rs +22 -6
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +21 -67
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +2 -2
- package/contracts/oapps/counter/Cargo.toml +5 -6
- package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
- package/contracts/oapps/counter/integration_tests/utils.rs +19 -12
- package/contracts/oapps/oapp/src/errors.rs +1 -1
- package/contracts/oapps/oapp/src/interfaces/mod.rs +3 -0
- package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +47 -0
- package/contracts/oapps/oapp/src/lib.rs +1 -0
- package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +4 -4
- package/contracts/oapps/oapp/src/oapp_core.rs +5 -5
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +12 -4
- package/contracts/oapps/oapp/src/oapp_receiver.rs +14 -9
- package/contracts/oapps/oapp/src/tests/mod.rs +4 -4
- package/contracts/oapps/oapp/src/tests/oapp_core.rs +223 -0
- package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +240 -0
- package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +381 -0
- package/contracts/oapps/oapp/src/tests/oapp_sender.rs +569 -0
- package/contracts/oapps/oapp-macros/Cargo.toml +8 -4
- package/contracts/oapps/oapp-macros/src/generators.rs +9 -34
- package/contracts/oapps/oapp-macros/src/lib.rs +3 -0
- package/contracts/oapps/oapp-macros/src/tests/mod.rs +2 -0
- package/contracts/oapps/oapp-macros/src/tests/oapp.rs +88 -0
- package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +86 -0
- package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +103 -0
- package/contracts/oapps/oft/integration-tests/utils.rs +28 -8
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +153 -75
- package/contracts/oapps/oft/src/extensions/pausable.rs +61 -12
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +198 -134
- package/contracts/oapps/oft/src/oft.rs +45 -50
- package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +1 -1
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +4 -26
- package/contracts/oapps/oft-core/Cargo.toml +1 -4
- package/contracts/oapps/oft-core/integration-tests/setup.rs +3 -3
- package/contracts/oapps/oft-core/integration-tests/utils.rs +21 -3
- package/contracts/oapps/oft-core/src/errors.rs +3 -2
- package/contracts/oapps/oft-core/src/events.rs +6 -0
- package/contracts/oapps/oft-core/src/lib.rs +1 -1
- package/contracts/oapps/oft-core/src/oft_core.rs +341 -246
- package/contracts/oapps/oft-core/src/storage.rs +7 -3
- package/contracts/oapps/oft-core/src/tests/mod.rs +1 -0
- package/contracts/oapps/oft-core/src/tests/test_decimals.rs +37 -2
- package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +2 -2
- package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +323 -0
- package/contracts/oapps/oft-core/src/tests/test_send.rs +2 -2
- package/contracts/oapps/oft-core/src/tests/test_utils.rs +61 -16
- package/contracts/upgrader/src/lib.rs +30 -57
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
- package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
- package/contracts/utils/Cargo.toml +0 -1
- package/contracts/utils/src/buffer_reader.rs +1 -0
- package/contracts/utils/src/errors.rs +4 -2
- package/contracts/utils/src/multisig.rs +17 -8
- package/contracts/utils/src/ownable.rs +6 -6
- package/contracts/utils/src/testing_utils.rs +124 -54
- package/contracts/utils/src/tests/multisig.rs +12 -12
- package/contracts/utils/src/tests/ownable.rs +6 -6
- package/contracts/utils/src/tests/testing_utils.rs +50 -167
- package/contracts/utils/src/tests/ttl_configurable.rs +5 -5
- package/contracts/utils/src/tests/upgradeable.rs +372 -175
- package/contracts/utils/src/ttl_configurable.rs +13 -7
- package/contracts/utils/src/upgradeable.rs +48 -23
- package/contracts/workers/dvn/Cargo.toml +6 -6
- package/contracts/workers/dvn/src/auth.rs +12 -42
- package/contracts/workers/dvn/src/dvn.rs +15 -40
- package/contracts/workers/dvn/src/errors.rs +0 -1
- package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
- package/contracts/workers/dvn/src/lib.rs +4 -3
- package/contracts/workers/dvn/src/tests/auth.rs +1 -1
- package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
- package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
- package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
- package/contracts/workers/dvn/src/tests/setup.rs +5 -9
- package/contracts/workers/dvn-fee-lib/Cargo.toml +2 -2
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +38 -22
- package/contracts/workers/dvn-fee-lib/src/lib.rs +12 -2
- package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +17 -16
- package/contracts/workers/executor/Cargo.toml +4 -0
- package/contracts/workers/executor/src/executor.rs +15 -36
- package/contracts/workers/executor/src/lib.rs +2 -2
- package/contracts/workers/executor/src/tests/auth.rs +394 -0
- package/contracts/workers/executor/src/tests/executor.rs +410 -0
- package/contracts/workers/executor/src/tests/mod.rs +3 -0
- package/contracts/workers/executor/src/tests/setup.rs +250 -0
- package/contracts/workers/executor-fee-lib/Cargo.toml +7 -1
- package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +62 -15
- package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
- package/contracts/workers/executor-fee-lib/src/lib.rs +11 -2
- package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
- package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
- package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
- package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
- package/contracts/workers/executor-helper/Cargo.toml +0 -1
- package/contracts/workers/executor-helper/src/lib.rs +3 -0
- package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
- package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
- package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
- package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
- package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
- package/contracts/workers/price-feed/Cargo.toml +7 -1
- package/contracts/workers/price-feed/src/events.rs +1 -1
- package/contracts/workers/price-feed/src/lib.rs +12 -4
- package/contracts/workers/price-feed/src/price_feed.rs +5 -21
- package/contracts/workers/price-feed/src/storage.rs +1 -1
- package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
- package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
- package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
- package/contracts/workers/price-feed/src/types.rs +1 -1
- package/contracts/workers/worker/src/errors.rs +1 -4
- package/contracts/workers/worker/src/lib.rs +0 -2
- package/contracts/workers/worker/src/storage.rs +32 -29
- package/contracts/workers/worker/src/tests/setup.rs +2 -8
- package/contracts/workers/worker/src/tests/worker.rs +96 -74
- package/contracts/workers/worker/src/worker.rs +75 -75
- package/docs/error-spec.md +55 -0
- package/docs/layerzero-v2-on-stellar.md +447 -0
- package/docs/oapp-guide.md +212 -0
- package/docs/oft-guide.md +314 -0
- package/package.json +3 -3
- package/sdk/.turbo/turbo-test.log +268 -263
- package/sdk/dist/generated/bml.d.ts +12 -4
- package/sdk/dist/generated/bml.js +9 -7
- package/sdk/dist/generated/counter.d.ts +306 -298
- package/sdk/dist/generated/counter.js +48 -46
- package/sdk/dist/generated/dvn.d.ts +450 -411
- package/sdk/dist/generated/dvn.js +66 -64
- package/sdk/dist/generated/dvn_fee_lib.d.ts +294 -338
- package/sdk/dist/generated/dvn_fee_lib.js +33 -64
- package/sdk/dist/generated/endpoint.d.ts +108 -100
- package/sdk/dist/generated/endpoint.js +21 -19
- package/sdk/dist/generated/executor.d.ts +414 -370
- package/sdk/dist/generated/executor.js +58 -55
- package/sdk/dist/generated/executor_fee_lib.d.ts +333 -377
- package/sdk/dist/generated/executor_fee_lib.js +34 -65
- package/sdk/dist/generated/executor_helper.d.ts +26 -190
- package/sdk/dist/generated/executor_helper.js +23 -28
- package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
- package/sdk/dist/generated/layerzero_view.js +294 -0
- package/sdk/dist/generated/oft.d.ts +408 -385
- package/sdk/dist/generated/oft.js +89 -92
- package/sdk/dist/generated/price_feed.d.ts +385 -429
- package/sdk/dist/generated/price_feed.js +50 -81
- package/sdk/dist/generated/sml.d.ts +108 -100
- package/sdk/dist/generated/sml.js +21 -19
- package/sdk/dist/generated/treasury.d.ts +108 -100
- package/sdk/dist/generated/treasury.js +21 -19
- package/sdk/dist/generated/uln302.d.ts +108 -100
- package/sdk/dist/generated/uln302.js +23 -21
- package/sdk/dist/generated/upgrader.d.ts +189 -18
- package/sdk/dist/generated/upgrader.js +84 -4
- package/sdk/dist/index.d.ts +1 -0
- package/sdk/dist/index.js +2 -0
- package/sdk/package.json +1 -1
- package/sdk/src/index.ts +3 -0
- package/sdk/test/oft-sml.test.ts +4 -4
- package/sdk/test/suites/localnet.ts +84 -20
- package/sdk/test/upgrader.test.ts +2 -3
- package/tools/ts-bindings-gen/src/main.rs +2 -1
- package/contracts/ERROR_SPEC.md +0 -44
- package/contracts/endpoint-v2/ARCHITECTURE.md +0 -233
- package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +0 -175
- package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +0 -212
- package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +0 -153
- package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +0 -294
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
use common_macros::{contract_error, contract_trait, only_auth, storage};
|
|
2
2
|
use soroban_sdk::{assert_with_error, contractevent, Env};
|
|
3
|
-
use utils::
|
|
3
|
+
use utils::auth::Auth;
|
|
4
|
+
|
|
5
|
+
// =========================================================================
|
|
6
|
+
// Storage
|
|
7
|
+
// =========================================================================
|
|
4
8
|
|
|
5
9
|
#[storage]
|
|
6
10
|
pub enum OFTPausableStorage {
|
|
@@ -9,42 +13,87 @@ pub enum OFTPausableStorage {
|
|
|
9
13
|
Paused,
|
|
10
14
|
}
|
|
11
15
|
|
|
16
|
+
// =========================================================================
|
|
17
|
+
// Errors
|
|
18
|
+
// =========================================================================
|
|
19
|
+
|
|
12
20
|
#[contract_error]
|
|
13
21
|
pub enum OFTPausableError {
|
|
14
|
-
Paused =
|
|
22
|
+
Paused = 3110,
|
|
15
23
|
PauseStatusUnchanged,
|
|
16
24
|
}
|
|
17
25
|
|
|
26
|
+
// =========================================================================
|
|
27
|
+
// Events
|
|
28
|
+
// =========================================================================
|
|
29
|
+
|
|
18
30
|
#[contractevent]
|
|
19
31
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
20
32
|
pub struct PausedSet {
|
|
21
33
|
pub paused: bool,
|
|
22
34
|
}
|
|
23
35
|
|
|
36
|
+
// =========================================================================
|
|
37
|
+
// Trait With Default Implementations
|
|
38
|
+
// =========================================================================
|
|
39
|
+
|
|
24
40
|
#[contract_trait]
|
|
25
|
-
pub trait OFTPausable: OFTPausableInternal +
|
|
41
|
+
pub trait OFTPausable: OFTPausableInternal + Auth {
|
|
42
|
+
/// Sets the paused state of the OFT.
|
|
43
|
+
///
|
|
44
|
+
/// When paused, the OFT will reject new send/receive/quote_send/quote_oft operations.
|
|
45
|
+
///
|
|
46
|
+
/// # Arguments
|
|
47
|
+
/// * `paused` - `true` to pause, `false` to unpause
|
|
26
48
|
#[only_auth]
|
|
27
|
-
fn set_paused(env: &Env, paused: bool) {
|
|
28
|
-
|
|
29
|
-
assert_with_error!(env, current_paused != paused, OFTPausableError::PauseStatusUnchanged);
|
|
30
|
-
OFTPausableStorage::set_paused(env, &paused);
|
|
31
|
-
PausedSet { paused }.publish(env);
|
|
49
|
+
fn set_paused(env: &soroban_sdk::Env, paused: bool) {
|
|
50
|
+
Self::__set_paused(env, paused);
|
|
32
51
|
}
|
|
33
52
|
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
/// Returns the paused state of the OFT.
|
|
54
|
+
fn is_paused(env: &soroban_sdk::Env) -> bool {
|
|
55
|
+
Self::__is_paused(env)
|
|
36
56
|
}
|
|
37
57
|
}
|
|
38
58
|
|
|
39
59
|
/// Internal trait for pausable operations used by OFT hooks.
|
|
40
60
|
/// Contains only truly internal methods that are called from OFTInternal implementations.
|
|
41
61
|
pub trait OFTPausableInternal {
|
|
62
|
+
// =========================================================================
|
|
63
|
+
// OFT Hooks
|
|
64
|
+
// =========================================================================
|
|
65
|
+
|
|
42
66
|
/// Asserts that the OFT is not paused, panics otherwise.
|
|
43
|
-
/// Used internally by `send`, `quote_send`, and `__lz_receive` to enforce pause state.
|
|
67
|
+
/// Used internally by `send`, `quote_send`, `quote_oft`, and `__lz_receive` to enforce pause state.
|
|
44
68
|
///
|
|
45
69
|
/// # Errors
|
|
46
70
|
/// * `Paused` - If the OFT is currently paused.
|
|
47
71
|
fn __assert_not_paused(env: &Env) {
|
|
48
|
-
assert_with_error!(env, !
|
|
72
|
+
assert_with_error!(env, !Self::__is_paused(env), OFTPausableError::Paused);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// =========================================================================
|
|
76
|
+
// Management Functions
|
|
77
|
+
// =========================================================================
|
|
78
|
+
|
|
79
|
+
/// Sets the paused state of the OFT.
|
|
80
|
+
///
|
|
81
|
+
/// When paused, the OFT will reject new send/receive/quote_send/quote_oft operations.
|
|
82
|
+
///
|
|
83
|
+
/// # Arguments
|
|
84
|
+
/// * `paused` - `true` to pause, `false` to unpause
|
|
85
|
+
fn __set_paused(env: &Env, paused: bool) {
|
|
86
|
+
assert_with_error!(env, Self::__is_paused(env) != paused, OFTPausableError::PauseStatusUnchanged);
|
|
87
|
+
OFTPausableStorage::set_paused(env, &paused);
|
|
88
|
+
PausedSet { paused }.publish(env);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// =========================================================================
|
|
92
|
+
// View Functions
|
|
93
|
+
// =========================================================================
|
|
94
|
+
|
|
95
|
+
/// Returns the paused state of the OFT.
|
|
96
|
+
fn __is_paused(env: &Env) -> bool {
|
|
97
|
+
OFTPausableStorage::paused(env)
|
|
49
98
|
}
|
|
50
99
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
use crate as oft;
|
|
1
2
|
use common_macros::{contract_error, contract_trait, only_auth, storage};
|
|
2
|
-
use soroban_sdk::{assert_with_error, contractevent, contracttype,
|
|
3
|
-
use utils::
|
|
3
|
+
use soroban_sdk::{assert_with_error, contractevent, contracttype, Env};
|
|
4
|
+
use utils::auth::Auth;
|
|
5
|
+
|
|
6
|
+
// =========================================================================
|
|
7
|
+
// Types
|
|
8
|
+
// =========================================================================
|
|
4
9
|
|
|
5
10
|
#[contracttype]
|
|
6
11
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
@@ -10,191 +15,250 @@ pub enum Direction {
|
|
|
10
15
|
Outbound,
|
|
11
16
|
}
|
|
12
17
|
|
|
18
|
+
/// Configuration for rate limiting, used as input parameter.
|
|
13
19
|
#[contracttype]
|
|
14
20
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
15
|
-
pub struct
|
|
16
|
-
limit: i128,
|
|
17
|
-
window_seconds: u64,
|
|
21
|
+
pub struct RateLimitConfig {
|
|
22
|
+
pub limit: i128,
|
|
23
|
+
pub window_seconds: u64,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Internal storage struct for rate limit state.
|
|
27
|
+
///
|
|
28
|
+
/// The rate limiter uses a "leaky bucket" algorithm where:
|
|
29
|
+
/// - `config.limit` defines the maximum tokens that can be "in flight" at any time
|
|
30
|
+
/// - `config.window_seconds` defines how long it takes for the bucket to fully drain
|
|
31
|
+
/// - Tokens decay linearly over time: `decay = elapsed_time * limit / window_seconds`
|
|
32
|
+
/// - Current in-flight = `in_flight_on_last_update - decay` (clamped to 0)
|
|
33
|
+
#[contracttype]
|
|
34
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
35
|
+
struct RateLimitState {
|
|
36
|
+
/// The rate limit configuration (limit and window_seconds)
|
|
37
|
+
config: RateLimitConfig,
|
|
38
|
+
/// The in-flight amount at the time of `last_update` (before decay is applied)
|
|
18
39
|
in_flight_on_last_update: i128,
|
|
40
|
+
/// Timestamp of the last update (used to calculate decay)
|
|
19
41
|
last_update: u64,
|
|
20
42
|
}
|
|
21
43
|
|
|
44
|
+
// =========================================================================
|
|
45
|
+
// Storage
|
|
46
|
+
// =========================================================================
|
|
47
|
+
|
|
22
48
|
#[storage]
|
|
23
|
-
|
|
24
|
-
#[persistent(
|
|
49
|
+
enum RateLimitStorage {
|
|
50
|
+
#[persistent(RateLimitState)]
|
|
25
51
|
RateLimit { direction: Direction, eid: u32 },
|
|
26
52
|
}
|
|
27
53
|
|
|
54
|
+
// =========================================================================
|
|
55
|
+
// Errors
|
|
56
|
+
// =========================================================================
|
|
57
|
+
|
|
28
58
|
#[contract_error]
|
|
29
59
|
pub enum RateLimitError {
|
|
30
|
-
ExceededRateLimit =
|
|
60
|
+
ExceededRateLimit = 3120,
|
|
61
|
+
InvalidAmount,
|
|
31
62
|
InvalidTimestamp,
|
|
32
|
-
|
|
33
|
-
InvalidLimit,
|
|
63
|
+
InvalidConfig,
|
|
34
64
|
SameValue,
|
|
35
65
|
}
|
|
36
66
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
pub direction: Direction,
|
|
41
|
-
pub eid: u32,
|
|
42
|
-
pub limit: i128,
|
|
43
|
-
pub window_seconds: u64,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
#[contractevent]
|
|
47
|
-
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
48
|
-
pub struct RateLimitUpdated {
|
|
49
|
-
pub direction: Direction,
|
|
50
|
-
pub eid: u32,
|
|
51
|
-
pub limit: i128,
|
|
52
|
-
pub window_seconds: u64,
|
|
53
|
-
}
|
|
67
|
+
// =========================================================================
|
|
68
|
+
// Events
|
|
69
|
+
// =========================================================================
|
|
54
70
|
|
|
55
71
|
#[contractevent]
|
|
56
72
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
57
|
-
pub struct
|
|
73
|
+
pub struct RateLimitSet {
|
|
58
74
|
pub direction: Direction,
|
|
59
75
|
pub eid: u32,
|
|
76
|
+
/// The rate limit configuration, or None if the rate limit is removed
|
|
77
|
+
pub config: Option<RateLimitConfig>,
|
|
60
78
|
}
|
|
61
79
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if !RateLimitStorage::has_rate_limit(env, direction, eid) {
|
|
66
|
-
return 0;
|
|
67
|
-
}
|
|
68
|
-
let rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
|
|
69
|
-
let timestamp = env.ledger().timestamp();
|
|
70
|
-
assert_with_error!(env, timestamp >= rate_limit.last_update, RateLimitError::InvalidTimestamp);
|
|
71
|
-
let elapsed = timestamp - rate_limit.last_update;
|
|
72
|
-
let decay = (elapsed as i128) * rate_limit.limit / (rate_limit.window_seconds as i128);
|
|
73
|
-
if decay < rate_limit.in_flight_on_last_update {
|
|
74
|
-
rate_limit.in_flight_on_last_update - decay
|
|
75
|
-
} else {
|
|
76
|
-
0
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/// Checkpoints the current in-flight amount by applying decay and updating timestamp.
|
|
81
|
-
/// Used internally before modifying rate limit state.
|
|
82
|
-
fn checkpoint_rate_limit_in_flight(env: &Env, direction: &Direction, eid: u32) {
|
|
83
|
-
let in_flight = calculate_in_flight(env, direction, eid);
|
|
84
|
-
let mut rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
|
|
85
|
-
rate_limit.in_flight_on_last_update = in_flight;
|
|
86
|
-
rate_limit.last_update = env.ledger().timestamp();
|
|
87
|
-
RateLimitStorage::set_rate_limit(env, direction, eid, &rate_limit);
|
|
88
|
-
}
|
|
80
|
+
// =========================================================================
|
|
81
|
+
// Trait With Default Implementations
|
|
82
|
+
// =========================================================================
|
|
89
83
|
|
|
90
84
|
#[contract_trait]
|
|
91
|
-
pub trait RateLimiter: RateLimiterInternal +
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
assert_with_error!(env, window_seconds > 0, RateLimitError::InvalidWindowSeconds);
|
|
96
|
-
if RateLimitStorage::has_rate_limit(env, direction, eid) {
|
|
97
|
-
let rate_limit_data = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
|
|
98
|
-
assert_with_error!(
|
|
99
|
-
env,
|
|
100
|
-
limit != rate_limit_data.limit || window_seconds != rate_limit_data.window_seconds,
|
|
101
|
-
RateLimitError::SameValue
|
|
102
|
-
);
|
|
103
|
-
checkpoint_rate_limit_in_flight(env, direction, eid);
|
|
104
|
-
let mut rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
|
|
105
|
-
rate_limit.limit = limit;
|
|
106
|
-
rate_limit.window_seconds = window_seconds;
|
|
107
|
-
RateLimitStorage::set_rate_limit(env, direction, eid, &rate_limit);
|
|
108
|
-
RateLimitUpdated { direction: direction.clone(), eid, limit, window_seconds }.publish(env);
|
|
109
|
-
} else {
|
|
110
|
-
RateLimitStorage::set_rate_limit(
|
|
111
|
-
env,
|
|
112
|
-
direction,
|
|
113
|
-
eid,
|
|
114
|
-
&RateLimit {
|
|
115
|
-
limit,
|
|
116
|
-
window_seconds,
|
|
117
|
-
in_flight_on_last_update: 0,
|
|
118
|
-
last_update: env.ledger().timestamp(),
|
|
119
|
-
},
|
|
120
|
-
);
|
|
121
|
-
RateLimitSet { direction: direction.clone(), eid, limit, window_seconds }.publish(env);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
85
|
+
pub trait RateLimiter: RateLimiterInternal + Auth {
|
|
86
|
+
// =========================================================================
|
|
87
|
+
// Management Functions
|
|
88
|
+
// =========================================================================
|
|
124
89
|
|
|
90
|
+
/// Sets or removes a rate limit for a specific direction and endpoint.
|
|
91
|
+
///
|
|
92
|
+
/// # Arguments
|
|
93
|
+
/// * `direction` - The direction (Inbound or Outbound)
|
|
94
|
+
/// * `eid` - The endpoint ID
|
|
95
|
+
/// * `config` - The rate limit configuration, or None to remove the rate limit
|
|
125
96
|
#[only_auth]
|
|
126
|
-
fn
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
97
|
+
fn set_rate_limit(
|
|
98
|
+
env: &soroban_sdk::Env,
|
|
99
|
+
direction: &oft::rate_limiter::Direction,
|
|
100
|
+
eid: u32,
|
|
101
|
+
config: Option<oft::rate_limiter::RateLimitConfig>,
|
|
102
|
+
) {
|
|
103
|
+
Self::__set_rate_limit(env, direction, eid, config);
|
|
130
104
|
}
|
|
131
105
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
106
|
+
// =========================================================================
|
|
107
|
+
// View Functions
|
|
108
|
+
// =========================================================================
|
|
109
|
+
|
|
110
|
+
/// Returns the rate limit configuration for a direction and endpoint.
|
|
111
|
+
/// Returns None if no rate limit is configured.
|
|
112
|
+
fn rate_limit_config(
|
|
113
|
+
env: &soroban_sdk::Env,
|
|
114
|
+
direction: &oft::rate_limiter::Direction,
|
|
115
|
+
eid: u32,
|
|
116
|
+
) -> Option<oft::rate_limiter::RateLimitConfig> {
|
|
117
|
+
Self::__rate_limit_config(env, direction, eid)
|
|
138
118
|
}
|
|
139
119
|
|
|
140
|
-
|
|
141
|
-
|
|
120
|
+
/// Returns the current in-flight amount for a direction and endpoint.
|
|
121
|
+
fn rate_limit_in_flight(env: &soroban_sdk::Env, direction: &oft::rate_limiter::Direction, eid: u32) -> i128 {
|
|
122
|
+
Self::__rate_limit_in_flight(env, direction, eid)
|
|
142
123
|
}
|
|
143
124
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
let rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
|
|
149
|
-
let in_flight = calculate_in_flight(env, direction, eid);
|
|
150
|
-
if rate_limit.limit > in_flight {
|
|
151
|
-
rate_limit.limit - in_flight
|
|
152
|
-
} else {
|
|
153
|
-
0
|
|
154
|
-
}
|
|
125
|
+
/// Returns the available capacity for a direction and endpoint.
|
|
126
|
+
/// Returns i128::MAX if no rate limit is configured.
|
|
127
|
+
fn rate_limit_capacity(env: &soroban_sdk::Env, direction: &oft::rate_limiter::Direction, eid: u32) -> i128 {
|
|
128
|
+
Self::__rate_limit_capacity(env, direction, eid)
|
|
155
129
|
}
|
|
156
130
|
}
|
|
157
131
|
|
|
158
132
|
/// Internal trait for rate limiter operations used by OFT hooks.
|
|
159
133
|
/// Contains only truly internal methods that are called from OFTInternal implementations.
|
|
160
134
|
pub trait RateLimiterInternal {
|
|
135
|
+
// =========================================================================
|
|
136
|
+
// OFT Hooks
|
|
137
|
+
// =========================================================================
|
|
138
|
+
|
|
161
139
|
/// Consumes the specified amount from the rate limit capacity.
|
|
162
140
|
/// Used internally by `__debit` and `__credit` to enforce rate limits.
|
|
163
141
|
///
|
|
164
142
|
/// # Errors
|
|
165
143
|
/// * `ExceededRateLimit` - If the amount exceeds the available capacity.
|
|
166
144
|
fn __consume_rate_limit_capacity(env: &Env, direction: &Direction, eid: u32, amount: i128) {
|
|
167
|
-
|
|
145
|
+
assert_with_error!(env, amount >= 0, RateLimitError::InvalidAmount);
|
|
146
|
+
|
|
147
|
+
let Some(mut state) = RateLimitStorage::rate_limit(env, direction, eid) else {
|
|
168
148
|
return;
|
|
169
|
-
}
|
|
170
|
-
checkpoint_rate_limit_in_flight(env, direction, eid);
|
|
171
|
-
let mut rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
|
|
172
|
-
// Check against remaining capacity (limit - current in_flight), not total limit
|
|
173
|
-
let capacity = if rate_limit.limit > rate_limit.in_flight_on_last_update {
|
|
174
|
-
rate_limit.limit - rate_limit.in_flight_on_last_update
|
|
175
|
-
} else {
|
|
176
|
-
0
|
|
177
149
|
};
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
150
|
+
|
|
151
|
+
// Apply decay and update timestamp
|
|
152
|
+
let in_flight = calculate_decayed_in_flight(env, &state);
|
|
153
|
+
state.in_flight_on_last_update = in_flight;
|
|
154
|
+
state.last_update = env.ledger().timestamp();
|
|
155
|
+
|
|
156
|
+
// Check capacity and consume
|
|
157
|
+
let capacity = (state.config.limit - in_flight).max(0);
|
|
158
|
+
assert_with_error!(env, amount <= capacity, RateLimitError::ExceededRateLimit);
|
|
159
|
+
state.in_flight_on_last_update += amount;
|
|
160
|
+
|
|
161
|
+
RateLimitStorage::set_rate_limit(env, direction, eid, &state);
|
|
183
162
|
}
|
|
184
163
|
|
|
185
164
|
/// Releases the specified amount back to the rate limit capacity.
|
|
186
165
|
/// Used internally by `__credit` to release outbound capacity on inbound messages.
|
|
187
166
|
fn __release_rate_limit_capacity(env: &Env, direction: &Direction, eid: u32, amount: i128) {
|
|
188
|
-
|
|
167
|
+
assert_with_error!(env, amount >= 0, RateLimitError::InvalidAmount);
|
|
168
|
+
|
|
169
|
+
let Some(mut state) = RateLimitStorage::rate_limit(env, direction, eid) else {
|
|
189
170
|
return;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// Apply decay and update timestamp
|
|
174
|
+
let in_flight = calculate_decayed_in_flight(env, &state);
|
|
175
|
+
state.in_flight_on_last_update = (in_flight - amount).max(0);
|
|
176
|
+
state.last_update = env.ledger().timestamp();
|
|
177
|
+
|
|
178
|
+
RateLimitStorage::set_rate_limit(env, direction, eid, &state);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// =========================================================================
|
|
182
|
+
// Management Functions
|
|
183
|
+
// =========================================================================
|
|
184
|
+
|
|
185
|
+
/// Sets or removes a rate limit for a specific direction and endpoint.
|
|
186
|
+
///
|
|
187
|
+
/// # Arguments
|
|
188
|
+
/// * `direction` - The direction (Inbound or Outbound)
|
|
189
|
+
/// * `eid` - The endpoint ID
|
|
190
|
+
/// * `config` - The rate limit configuration, or None to remove the rate limit
|
|
191
|
+
fn __set_rate_limit(env: &Env, direction: &Direction, eid: u32, config: Option<RateLimitConfig>) {
|
|
192
|
+
let current_state = RateLimitStorage::rate_limit(env, direction, eid);
|
|
193
|
+
let current_config = current_state.as_ref().map(|s| s.config.clone());
|
|
194
|
+
assert_with_error!(env, current_config != config, RateLimitError::SameValue);
|
|
195
|
+
|
|
196
|
+
match config {
|
|
197
|
+
Some(cfg) => {
|
|
198
|
+
assert_with_error!(env, cfg.limit >= 0 && cfg.window_seconds > 0, RateLimitError::InvalidConfig);
|
|
199
|
+
|
|
200
|
+
let state = if let Some(mut existing) = current_state {
|
|
201
|
+
// Update existing: checkpoint in-flight before changing config
|
|
202
|
+
existing.in_flight_on_last_update = calculate_decayed_in_flight(env, &existing);
|
|
203
|
+
existing.last_update = env.ledger().timestamp();
|
|
204
|
+
existing.config = cfg.clone();
|
|
205
|
+
existing
|
|
206
|
+
} else {
|
|
207
|
+
// Create new
|
|
208
|
+
RateLimitState {
|
|
209
|
+
config: cfg.clone(),
|
|
210
|
+
in_flight_on_last_update: 0,
|
|
211
|
+
last_update: env.ledger().timestamp(),
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
RateLimitStorage::set_rate_limit(env, direction, eid, &state);
|
|
216
|
+
RateLimitSet { direction: direction.clone(), eid, config: Some(cfg) }.publish(env);
|
|
217
|
+
}
|
|
218
|
+
None => {
|
|
219
|
+
RateLimitStorage::remove_rate_limit(env, direction, eid);
|
|
220
|
+
RateLimitSet { direction: direction.clone(), eid, config: None }.publish(env);
|
|
221
|
+
}
|
|
190
222
|
}
|
|
191
|
-
checkpoint_rate_limit_in_flight(env, direction, eid);
|
|
192
|
-
let mut rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
|
|
193
|
-
if amount >= rate_limit.in_flight_on_last_update {
|
|
194
|
-
rate_limit.in_flight_on_last_update = 0;
|
|
195
|
-
} else {
|
|
196
|
-
rate_limit.in_flight_on_last_update -= amount;
|
|
197
|
-
}
|
|
198
|
-
RateLimitStorage::set_rate_limit(env, direction, eid, &rate_limit);
|
|
199
223
|
}
|
|
224
|
+
|
|
225
|
+
// =========================================================================
|
|
226
|
+
// View Functions
|
|
227
|
+
// =========================================================================
|
|
228
|
+
|
|
229
|
+
/// Returns the rate limit configuration for a direction and endpoint.
|
|
230
|
+
/// Returns None if no rate limit is configured.
|
|
231
|
+
fn __rate_limit_config(env: &Env, direction: &Direction, eid: u32) -> Option<RateLimitConfig> {
|
|
232
|
+
RateLimitStorage::rate_limit(env, direction, eid).map(|s| s.config)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/// Returns the current in-flight amount for a direction and endpoint.
|
|
236
|
+
fn __rate_limit_in_flight(env: &Env, direction: &Direction, eid: u32) -> i128 {
|
|
237
|
+
RateLimitStorage::rate_limit(env, direction, eid).map(|s| calculate_decayed_in_flight(env, &s)).unwrap_or(0)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/// Returns the available capacity for a direction and endpoint.
|
|
241
|
+
/// Returns i128::MAX if no rate limit is configured.
|
|
242
|
+
fn __rate_limit_capacity(env: &Env, direction: &Direction, eid: u32) -> i128 {
|
|
243
|
+
RateLimitStorage::rate_limit(env, direction, eid)
|
|
244
|
+
.map(|s| (s.config.limit - calculate_decayed_in_flight(env, &s)).max(0))
|
|
245
|
+
.unwrap_or(i128::MAX)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// =========================================================================
|
|
250
|
+
// Helper Functions
|
|
251
|
+
// =========================================================================
|
|
252
|
+
|
|
253
|
+
/// Calculates the current in-flight amount with decay applied.
|
|
254
|
+
/// This is a pure function that doesn't access storage.
|
|
255
|
+
fn calculate_decayed_in_flight(env: &Env, state: &RateLimitState) -> i128 {
|
|
256
|
+
let timestamp = env.ledger().timestamp();
|
|
257
|
+
assert_with_error!(env, timestamp >= state.last_update, RateLimitError::InvalidTimestamp);
|
|
258
|
+
|
|
259
|
+
let elapsed = timestamp - state.last_update;
|
|
260
|
+
let decay = (elapsed as i128) * state.config.limit / (state.config.window_seconds as i128);
|
|
261
|
+
|
|
262
|
+
// Ensure the decayed in-flight amount is not negative
|
|
263
|
+
(state.in_flight_on_last_update - decay).max(0)
|
|
200
264
|
}
|