@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,15 +1,15 @@
|
|
|
1
1
|
//! OFT - traits and implementations for Omnichain Fungible Tokens.
|
|
2
2
|
//!
|
|
3
3
|
//! This module provides:
|
|
4
|
-
//! - `OFTInternal`: Internal methods NOT exposed as contract entrypoints (`__debit`, `__credit`, etc.)
|
|
4
|
+
//! - `OFTInternal`: Internal methods NOT exposed as contract entrypoints (`__debit`, `__credit`, `__initialize_oft`, `__receive`, etc.)
|
|
5
5
|
//! - `OFTCore`: Public methods exposed as contract entrypoints (using `#[contracttrait]`)
|
|
6
|
-
//! -
|
|
6
|
+
//! - `impl_oft_lz_receive!`: Macro to implement `LzReceiveInternal` with default OFT receive logic
|
|
7
7
|
//!
|
|
8
8
|
//! ## Usage
|
|
9
9
|
//!
|
|
10
10
|
//! ```ignore
|
|
11
|
-
//! use oapp_macros::
|
|
12
|
-
//! use oft_core::{OFTInternal, OFTCore,
|
|
11
|
+
//! use oapp_macros::oapp;
|
|
12
|
+
//! use oft_core::{OFTInternal, OFTCore, impl_oft_lz_receive};
|
|
13
13
|
//!
|
|
14
14
|
//! #[oapp]
|
|
15
15
|
//! pub struct MyOFT;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
//! #[contractimpl]
|
|
18
18
|
//! impl MyOFT {
|
|
19
19
|
//! pub fn __constructor(env: &Env, token: &Address, owner: &Address, endpoint: &Address, delegate: &Option<Address>) {
|
|
20
|
-
//!
|
|
20
|
+
//! Self::__initialize_oft(env, owner, token, endpoint, delegate, 6)
|
|
21
21
|
//! }
|
|
22
22
|
//! }
|
|
23
23
|
//!
|
|
@@ -38,26 +38,30 @@
|
|
|
38
38
|
//! oft_core::oft_types::mint_burn::credit::<Self>(env, to, amount_ld, src_eid)
|
|
39
39
|
//! }
|
|
40
40
|
//! }
|
|
41
|
+
//!
|
|
42
|
+
//! // LzReceiveInternal - use the macro for default OFT receive logic
|
|
43
|
+
//! impl_oft_lz_receive!(MyOFT);
|
|
41
44
|
//! ```
|
|
42
45
|
|
|
43
46
|
use crate::{
|
|
44
47
|
self as oft_core,
|
|
45
48
|
codec::{oft_compose_msg_codec::OFTComposeMsg, oft_msg_codec::OFTMessage},
|
|
46
49
|
errors::OFTError,
|
|
47
|
-
events::{self, OFTSent},
|
|
50
|
+
events::{self, MsgInspectorSet, OFTSent},
|
|
48
51
|
storage::OFTStorage,
|
|
49
52
|
types::{self, OFTFeeDetail, OFTLimit, OFTReceipt, SendParam},
|
|
50
53
|
utils as oft_utils,
|
|
51
54
|
};
|
|
52
|
-
use common_macros::contract_trait;
|
|
53
|
-
use endpoint_v2::{MessagingComposerClient, MessagingFee, MessagingReceipt
|
|
55
|
+
use common_macros::{contract_trait, only_auth};
|
|
56
|
+
use endpoint_v2::{MessagingComposerClient, MessagingFee, MessagingReceipt};
|
|
54
57
|
use oapp::{
|
|
58
|
+
interfaces::OAppMsgInspectorClient,
|
|
55
59
|
oapp_core::{initialize_oapp, OAppCore},
|
|
56
60
|
oapp_options_type3::OAppOptionsType3,
|
|
57
61
|
oapp_receiver::OAppReceiver,
|
|
58
62
|
oapp_sender::OAppSenderInternal,
|
|
59
63
|
};
|
|
60
|
-
use soroban_sdk::{assert_with_error, token::TokenClient, vec, Address, Bytes,
|
|
64
|
+
use soroban_sdk::{assert_with_error, token::TokenClient, vec, Address, Bytes, Env, Vec};
|
|
61
65
|
use utils::{option_ext::OptionExt, ownable::OwnableInitializer};
|
|
62
66
|
|
|
63
67
|
// ===========================================================================
|
|
@@ -78,11 +82,47 @@ use utils::{option_ext::OptionExt, ownable::OwnableInitializer};
|
|
|
78
82
|
/// impl OFTInternal for MyOFT { ... }
|
|
79
83
|
/// ```
|
|
80
84
|
///
|
|
81
|
-
///
|
|
82
|
-
///
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
/// This trait extends all OApp supertraits and contains both the token operations
|
|
86
|
+
/// and the internal sending logic. `OFTCore` serves only as an entrypoint wrapper.
|
|
87
|
+
pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOptionsType3 + OwnableInitializer {
|
|
88
|
+
// =========================================================================
|
|
89
|
+
// Initialization
|
|
90
|
+
// =========================================================================
|
|
91
|
+
|
|
92
|
+
/// Initializes the OFT (Omnichain Fungible Token) contract.
|
|
93
|
+
///
|
|
94
|
+
/// Sets up the OApp infrastructure and configures decimal conversion for cross-chain transfers.
|
|
95
|
+
/// The `shared_decimals` parameter defines the common decimal precision used across all chains,
|
|
96
|
+
/// enabling consistent token amounts regardless of each chain's native token decimals.
|
|
97
|
+
///
|
|
98
|
+
/// # Arguments
|
|
99
|
+
/// * `owner` - The address that will own this OFT contract
|
|
100
|
+
/// * `token` - The underlying token contract address (must implement SEP-41 token interface)
|
|
101
|
+
/// * `endpoint` - The LayerZero endpoint address for cross-chain messaging
|
|
102
|
+
/// * `delegate` - Optional delegate address for endpoint configuration permissions
|
|
103
|
+
/// * `shared_decimals` - The shared decimal precision for cross-chain compatibility (must be <= local decimals)
|
|
104
|
+
///
|
|
105
|
+
/// # Panics
|
|
106
|
+
/// * `OFTError::InvalidLocalDecimals` - If the token's local decimals are less than `shared_decimals`
|
|
107
|
+
fn __initialize_oft(
|
|
108
|
+
env: &Env,
|
|
109
|
+
owner: &Address,
|
|
110
|
+
token: &Address,
|
|
111
|
+
endpoint: &Address,
|
|
112
|
+
delegate: &Option<Address>,
|
|
113
|
+
shared_decimals: u32,
|
|
114
|
+
) {
|
|
115
|
+
// Initialize OApp (includes owner initialization)
|
|
116
|
+
initialize_oapp::<Self>(env, owner, endpoint, delegate);
|
|
117
|
+
|
|
118
|
+
let local_decimals = TokenClient::new(env, token).decimals();
|
|
119
|
+
assert_with_error!(env, local_decimals >= shared_decimals, OFTError::InvalidLocalDecimals);
|
|
120
|
+
|
|
121
|
+
// Initialize OFT storage
|
|
122
|
+
OFTStorage::set_token(env, token);
|
|
123
|
+
OFTStorage::set_decimals_diff(env, &(local_decimals - shared_decimals));
|
|
124
|
+
}
|
|
125
|
+
|
|
86
126
|
// =========================================================================
|
|
87
127
|
// Required Methods (no defaults - user MUST implement)
|
|
88
128
|
// =========================================================================
|
|
@@ -114,19 +154,239 @@ pub trait OFTInternal: OAppCore + OAppOptionsType3 {
|
|
|
114
154
|
// Optional Methods (have defaults - override as needed)
|
|
115
155
|
// =========================================================================
|
|
116
156
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
157
|
+
// ----- Quote Methods -----
|
|
158
|
+
|
|
159
|
+
/// Quotes an OFT transfer without executing.
|
|
160
|
+
///
|
|
161
|
+
/// The default implementation has no send limits (`min_amount_ld: 0`, `max_amount_ld: i128::MAX`)
|
|
162
|
+
/// and no fee details (empty vector). Override this method to implement custom limits or fees.
|
|
163
|
+
///
|
|
164
|
+
/// # Arguments
|
|
165
|
+
/// * `send_param` - The send parameters to quote
|
|
166
|
+
///
|
|
167
|
+
/// # Returns
|
|
168
|
+
/// A tuple of (transfer limits, fee details, estimated receipt)
|
|
169
|
+
fn __quote_oft(env: &Env, send_param: &SendParam) -> (OFTLimit, Vec<OFTFeeDetail>, OFTReceipt) {
|
|
170
|
+
assert_with_error!(env, send_param.amount_ld >= 0, OFTError::InvalidAmount);
|
|
171
|
+
|
|
172
|
+
let limit = OFTLimit { min_amount_ld: 0, max_amount_ld: i128::MAX };
|
|
173
|
+
let fee_details = vec![env];
|
|
174
|
+
let oft_receipt = Self::__debit_view(env, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
175
|
+
(limit, fee_details, oft_receipt)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// Quotes the LayerZero messaging fee for a send operation.
|
|
179
|
+
///
|
|
180
|
+
/// # Arguments
|
|
181
|
+
/// * `from` - The address initiating the transfer
|
|
182
|
+
/// * `send_param` - The send parameters to quote
|
|
183
|
+
/// * `pay_in_zro` - Whether to pay the fee in ZRO token
|
|
184
|
+
///
|
|
185
|
+
/// # Returns
|
|
186
|
+
/// The messaging fee required for the transfer
|
|
187
|
+
fn __quote_send(env: &Env, from: &Address, send_param: &SendParam, pay_in_zro: bool) -> MessagingFee {
|
|
188
|
+
assert_with_error!(env, send_param.amount_ld >= 0, OFTError::InvalidAmount);
|
|
189
|
+
|
|
190
|
+
let OFTReceipt { amount_received_ld, .. } =
|
|
191
|
+
Self::__debit_view(env, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
192
|
+
|
|
193
|
+
let (msg, options) = Self::__build_msg_and_options(env, from, send_param, amount_received_ld);
|
|
194
|
+
Self::__quote(env, send_param.dst_eid, &msg, &options, pay_in_zro)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ----- Send Method -----
|
|
198
|
+
|
|
199
|
+
/// Executes a cross-chain token transfer via LayerZero.
|
|
200
|
+
///
|
|
201
|
+
/// Debits tokens from the `from` address, builds the message, and sends via the endpoint.
|
|
202
|
+
/// The `from` address must be authenticated.
|
|
203
|
+
///
|
|
204
|
+
/// # Arguments
|
|
205
|
+
/// * `from` - The address sending tokens (must authorize)
|
|
206
|
+
/// * `send_param` - The send parameters (destination, recipient, amount, options)
|
|
207
|
+
/// * `fee` - The messaging fee to pay
|
|
208
|
+
/// * `refund_address` - The address to refund excess fees to
|
|
209
|
+
///
|
|
210
|
+
/// # Returns
|
|
211
|
+
/// A tuple of (messaging receipt, OFT receipt with amounts)
|
|
212
|
+
fn __send(
|
|
213
|
+
env: &Env,
|
|
214
|
+
from: &Address,
|
|
215
|
+
send_param: &SendParam,
|
|
216
|
+
fee: &MessagingFee,
|
|
217
|
+
refund_address: &Address,
|
|
218
|
+
) -> (MessagingReceipt, OFTReceipt) {
|
|
219
|
+
from.require_auth();
|
|
220
|
+
|
|
221
|
+
assert_with_error!(env, send_param.amount_ld >= 0, OFTError::InvalidAmount);
|
|
222
|
+
|
|
223
|
+
let oft_receipt = Self::__debit(env, from, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
224
|
+
|
|
225
|
+
let (msg, options) = Self::__build_msg_and_options(env, from, send_param, oft_receipt.amount_received_ld);
|
|
226
|
+
let msg_receipt = Self::__lz_send(env, send_param.dst_eid, &msg, &options, from, fee, refund_address);
|
|
227
|
+
|
|
228
|
+
OFTSent {
|
|
229
|
+
guid: msg_receipt.guid.clone(),
|
|
230
|
+
dst_eid: send_param.dst_eid,
|
|
231
|
+
from: from.clone(),
|
|
232
|
+
amount_sent_ld: oft_receipt.amount_sent_ld,
|
|
233
|
+
amount_received_ld: oft_receipt.amount_received_ld,
|
|
234
|
+
}
|
|
235
|
+
.publish(env);
|
|
236
|
+
|
|
237
|
+
(msg_receipt, oft_receipt)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ----- View/Helper Methods -----
|
|
241
|
+
|
|
242
|
+
/// Simulates a debit operation without executing, used for quoting.
|
|
243
|
+
///
|
|
244
|
+
/// The default implementation does not charge any fee, so `amount_sent_ld` equals
|
|
245
|
+
/// `amount_received_ld` (after dust removal). Override this method to implement
|
|
246
|
+
/// custom fee logic.
|
|
247
|
+
///
|
|
248
|
+
/// # Arguments
|
|
249
|
+
/// * `amount_ld` - The amount of tokens to send in local decimals
|
|
250
|
+
/// * `min_amount_ld` - The minimum amount to send in local decimals (slippage protection)
|
|
251
|
+
/// * `dst_eid` - The destination chain ID (unused in default implementation)
|
|
252
|
+
///
|
|
253
|
+
/// # Returns
|
|
254
|
+
/// `OFTReceipt` containing the amount sent and amount received after dust removal
|
|
255
|
+
///
|
|
256
|
+
/// # Panics
|
|
257
|
+
/// * `OFTError::SlippageExceeded` - If `amount_received_ld` is less than `min_amount_ld`
|
|
258
|
+
fn __debit_view(env: &Env, amount_ld: i128, min_amount_ld: i128, _dst_eid: u32) -> OFTReceipt {
|
|
259
|
+
let conversion_rate = Self::__decimal_conversion_rate(env);
|
|
260
|
+
let amount_sent_ld = oft_utils::remove_dust(amount_ld, conversion_rate);
|
|
261
|
+
let amount_received_ld = amount_sent_ld;
|
|
262
|
+
|
|
263
|
+
assert_with_error!(env, amount_received_ld >= min_amount_ld, OFTError::SlippageExceeded);
|
|
264
|
+
|
|
265
|
+
OFTReceipt { amount_sent_ld, amount_received_ld }
|
|
120
266
|
}
|
|
121
267
|
|
|
122
268
|
/// Builds OFT message and combines options for cross-chain transfer.
|
|
269
|
+
///
|
|
270
|
+
/// If a message inspector is set, it will be called to validate the message and options.
|
|
271
|
+
/// The inspector should panic if the message or options are invalid.
|
|
272
|
+
///
|
|
273
|
+
/// # Arguments
|
|
274
|
+
/// * `from` - The address initiating the transfer
|
|
275
|
+
/// * `send_param` - The send parameters including destination, recipient, and options
|
|
276
|
+
/// * `amount_receive_ld` - The amount to be received in local decimals (after dust removal)
|
|
277
|
+
///
|
|
278
|
+
/// # Returns
|
|
279
|
+
/// A tuple of (encoded message, combined options)
|
|
123
280
|
fn __build_msg_and_options(
|
|
124
281
|
env: &Env,
|
|
125
282
|
from: &Address,
|
|
126
|
-
send_param: &
|
|
127
|
-
|
|
283
|
+
send_param: &SendParam,
|
|
284
|
+
amount_receive_ld: i128,
|
|
128
285
|
) -> (Bytes, Bytes) {
|
|
129
|
-
|
|
286
|
+
let has_compose = !send_param.compose_msg.is_empty();
|
|
287
|
+
let conversion_rate = Self::__decimal_conversion_rate(env);
|
|
288
|
+
let (msg, _) = OFTMessage {
|
|
289
|
+
send_to: send_param.to.clone(),
|
|
290
|
+
amount_sd: oft_utils::to_sd(env, amount_receive_ld, conversion_rate),
|
|
291
|
+
compose_from: if has_compose { Some(oft_utils::address_payload(from)) } else { None },
|
|
292
|
+
compose_msg: if has_compose { Some(send_param.compose_msg.clone()) } else { None },
|
|
293
|
+
}
|
|
294
|
+
.encode(env);
|
|
295
|
+
let msg_type = if has_compose { types::SEND_AND_CALL } else { types::SEND };
|
|
296
|
+
let options = Self::combine_options(env, send_param.dst_eid, msg_type, &send_param.extra_options);
|
|
297
|
+
|
|
298
|
+
// Optionally inspect message and options if inspector is set
|
|
299
|
+
if let Some(inspector) = Self::__msg_inspector(env) {
|
|
300
|
+
OAppMsgInspectorClient::new(env, &inspector).inspect(&env.current_contract_address(), &msg, &options);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
(msg, options)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ----- Storage Accessors -----
|
|
307
|
+
|
|
308
|
+
/// Retrieves the token address associated with this OFT.
|
|
309
|
+
fn __token(env: &Env) -> Address {
|
|
310
|
+
OFTStorage::token(env).unwrap_or_panic(env, OFTError::NotInitialized)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/// Retrieves the decimal conversion rate used for cross-chain normalization.
|
|
314
|
+
fn __decimal_conversion_rate(env: &Env) -> i128 {
|
|
315
|
+
let decimals_diff = OFTStorage::decimals_diff(env).unwrap_or_panic(env, OFTError::NotInitialized);
|
|
316
|
+
10_i128.pow(decimals_diff)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/// Retrieves the shared decimals used for cross-chain normalization.
|
|
320
|
+
fn __shared_decimals(env: &Env) -> u32 {
|
|
321
|
+
let local_decimals = TokenClient::new(env, &Self::__token(env)).decimals();
|
|
322
|
+
let decimals_diff = OFTStorage::decimals_diff(env).unwrap_or_panic(env, OFTError::NotInitialized);
|
|
323
|
+
local_decimals - decimals_diff
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/// Returns the message inspector address if set.
|
|
327
|
+
fn __msg_inspector(env: &Env) -> Option<Address> {
|
|
328
|
+
OFTStorage::msg_inspector(env)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/// Sets or removes the message inspector address.
|
|
332
|
+
///
|
|
333
|
+
/// The message inspector is an optional contract that validates outgoing messages
|
|
334
|
+
/// and options before they are sent cross-chain. If set, the inspector's `inspect`
|
|
335
|
+
/// method will be called during `send` and `quote_send` operations.
|
|
336
|
+
///
|
|
337
|
+
/// # Arguments
|
|
338
|
+
/// * `inspector` - The address of the inspector contract, or None to remove
|
|
339
|
+
fn __set_msg_inspector(env: &Env, inspector: &Option<Address>) {
|
|
340
|
+
OFTStorage::set_or_remove_msg_inspector(env, inspector);
|
|
341
|
+
MsgInspectorSet { inspector: inspector.clone() }.publish(env);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ----- Receive Handler -----
|
|
345
|
+
|
|
346
|
+
/// Handles incoming cross-chain OFT transfer from LayerZero endpoint.
|
|
347
|
+
///
|
|
348
|
+
/// Credits tokens to the recipient and optionally queues a compose message.
|
|
349
|
+
/// Override this method to implement custom receive logic (e.g., pausable, rate limiting).
|
|
350
|
+
///
|
|
351
|
+
/// # Arguments
|
|
352
|
+
/// * `origin` - The origin information (source chain, sender, nonce)
|
|
353
|
+
/// * `guid` - The unique message identifier
|
|
354
|
+
/// * `message` - The encoded OFT message payload
|
|
355
|
+
/// * `extra_data` - Additional data (unused in default implementation)
|
|
356
|
+
/// * `executor` - The address of the executor handling the message (unused in default implementation)
|
|
357
|
+
/// * `value` - The native token value sent with the message (unused in default implementation)
|
|
358
|
+
fn __receive(
|
|
359
|
+
env: &Env,
|
|
360
|
+
origin: &endpoint_v2::Origin,
|
|
361
|
+
guid: &soroban_sdk::BytesN<32>,
|
|
362
|
+
message: &Bytes,
|
|
363
|
+
_extra_data: &Bytes,
|
|
364
|
+
_executor: &Address,
|
|
365
|
+
_value: i128,
|
|
366
|
+
) {
|
|
367
|
+
let oft_msg = OFTMessage::decode(message);
|
|
368
|
+
let send_to = oft_utils::resolve_address(env, &oft_msg.send_to);
|
|
369
|
+
|
|
370
|
+
let conversion_rate = Self::__decimal_conversion_rate(env);
|
|
371
|
+
let amount_received_ld =
|
|
372
|
+
Self::__credit(env, &send_to, oft_utils::to_ld(oft_msg.amount_sd, conversion_rate), origin.src_eid);
|
|
373
|
+
|
|
374
|
+
if oft_msg.is_composed() {
|
|
375
|
+
let compose_msg = OFTComposeMsg {
|
|
376
|
+
nonce: origin.nonce,
|
|
377
|
+
src_eid: origin.src_eid,
|
|
378
|
+
amount_ld: amount_received_ld,
|
|
379
|
+
compose_from: oft_msg.compose_from.unwrap(),
|
|
380
|
+
compose_msg: oft_msg.compose_msg.unwrap(),
|
|
381
|
+
}
|
|
382
|
+
.encode(env);
|
|
383
|
+
|
|
384
|
+
let endpoint_client = MessagingComposerClient::new(env, &Self::endpoint(env));
|
|
385
|
+
endpoint_client.send_compose(&env.current_contract_address(), &send_to, guid, &0, &compose_msg);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
events::OFTReceived { guid: guid.clone(), src_eid: origin.src_eid, to: send_to, amount_received_ld }
|
|
389
|
+
.publish(env);
|
|
130
390
|
}
|
|
131
391
|
}
|
|
132
392
|
|
|
@@ -139,13 +399,12 @@ pub trait OFTInternal: OAppCore + OAppOptionsType3 {
|
|
|
139
399
|
/// This trait is marked with `#[contracttrait]` so all its methods are exposed as
|
|
140
400
|
/// contract entrypoints. Users implement this with `#[contractimpl(contracttrait)]`.
|
|
141
401
|
///
|
|
142
|
-
///
|
|
143
|
-
/// are in the `OFTInternal` trait and are NOT exposed as contract entrypoints.
|
|
402
|
+
/// This trait only exposes entrypoints. All internal logic is in `OFTInternal`.
|
|
144
403
|
#[contract_trait(client_name = "OFTClient")]
|
|
145
|
-
pub trait OFTCore: OFTInternal
|
|
404
|
+
pub trait OFTCore: OFTInternal {
|
|
146
405
|
/// Retrieves the token address associated with this OFT.
|
|
147
406
|
fn token(env: &soroban_sdk::Env) -> soroban_sdk::Address {
|
|
148
|
-
|
|
407
|
+
Self::__token(env)
|
|
149
408
|
}
|
|
150
409
|
|
|
151
410
|
/// Returns OFT version as (major, minor).
|
|
@@ -155,12 +414,12 @@ pub trait OFTCore: OFTInternal + OAppReceiver + OAppSenderInternal + OAppOptions
|
|
|
155
414
|
|
|
156
415
|
/// Retrieves the shared decimals used for cross-chain normalization.
|
|
157
416
|
fn shared_decimals(env: &soroban_sdk::Env) -> u32 {
|
|
158
|
-
|
|
417
|
+
Self::__shared_decimals(env)
|
|
159
418
|
}
|
|
160
419
|
|
|
161
420
|
/// Retrieves the decimal conversion rate used for cross-chain normalization.
|
|
162
421
|
fn decimal_conversion_rate(env: &soroban_sdk::Env) -> i128 {
|
|
163
|
-
|
|
422
|
+
Self::__decimal_conversion_rate(env)
|
|
164
423
|
}
|
|
165
424
|
|
|
166
425
|
/// Whether a separate token approval is required before sending.
|
|
@@ -174,6 +433,24 @@ pub trait OFTCore: OFTInternal + OAppReceiver + OAppSenderInternal + OAppOptions
|
|
|
174
433
|
false
|
|
175
434
|
}
|
|
176
435
|
|
|
436
|
+
/// Returns the message inspector address if set.
|
|
437
|
+
fn msg_inspector(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
|
|
438
|
+
Self::__msg_inspector(env)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/// Sets or removes the message inspector address.
|
|
442
|
+
///
|
|
443
|
+
/// The message inspector is an optional contract that validates outgoing messages
|
|
444
|
+
/// and options before they are sent cross-chain. If set, the inspector's `inspect`
|
|
445
|
+
/// method will be called during `send` and `quote_send` operations.
|
|
446
|
+
///
|
|
447
|
+
/// # Arguments
|
|
448
|
+
/// * `inspector` - The address of the inspector contract, or None to remove
|
|
449
|
+
#[only_auth]
|
|
450
|
+
fn set_msg_inspector(env: &soroban_sdk::Env, inspector: &Option<soroban_sdk::Address>) {
|
|
451
|
+
Self::__set_msg_inspector(env, inspector);
|
|
452
|
+
}
|
|
453
|
+
|
|
177
454
|
/// Quotes an OFT transfer without executing.
|
|
178
455
|
///
|
|
179
456
|
/// # Returns
|
|
@@ -182,258 +459,76 @@ pub trait OFTCore: OFTInternal + OAppReceiver + OAppSenderInternal + OAppOptions
|
|
|
182
459
|
env: &soroban_sdk::Env,
|
|
183
460
|
send_param: &oft_core::types::SendParam,
|
|
184
461
|
) -> (oft_core::types::OFTLimit, soroban_sdk::Vec<oft_core::types::OFTFeeDetail>, oft_core::types::OFTReceipt) {
|
|
185
|
-
|
|
462
|
+
Self::__quote_oft(env, send_param)
|
|
186
463
|
}
|
|
187
464
|
|
|
188
465
|
/// Quotes a send operation including LayerZero messaging fees.
|
|
189
466
|
fn quote_send(
|
|
190
467
|
env: &soroban_sdk::Env,
|
|
191
|
-
|
|
468
|
+
from: &soroban_sdk::Address,
|
|
192
469
|
send_param: &oft_core::types::SendParam,
|
|
193
470
|
pay_in_zro: bool,
|
|
194
471
|
) -> endpoint_v2::MessagingFee {
|
|
195
|
-
|
|
472
|
+
Self::__quote_send(env, from, send_param, pay_in_zro)
|
|
196
473
|
}
|
|
197
474
|
|
|
198
475
|
/// Sends tokens cross-chain to another endpoint.
|
|
199
476
|
///
|
|
200
|
-
///
|
|
477
|
+
/// From must be authenticated.
|
|
201
478
|
///
|
|
202
479
|
/// # Returns
|
|
203
480
|
/// (MessagingReceipt, OFTReceipt)
|
|
204
481
|
fn send(
|
|
205
482
|
env: &soroban_sdk::Env,
|
|
206
|
-
|
|
483
|
+
from: &soroban_sdk::Address,
|
|
207
484
|
send_param: &oft_core::types::SendParam,
|
|
208
485
|
fee: &endpoint_v2::MessagingFee,
|
|
209
486
|
refund_address: &soroban_sdk::Address,
|
|
210
487
|
) -> (endpoint_v2::MessagingReceipt, oft_core::types::OFTReceipt) {
|
|
211
|
-
|
|
488
|
+
Self::__send(env, from, send_param, fee, refund_address)
|
|
212
489
|
}
|
|
213
490
|
}
|
|
214
491
|
|
|
215
492
|
// ===========================================================================
|
|
216
|
-
//
|
|
493
|
+
// LzReceive Handler (called by OAppReceiver)
|
|
217
494
|
// ===========================================================================
|
|
218
495
|
|
|
219
|
-
///
|
|
220
|
-
///
|
|
221
|
-
/// Sets up the OApp infrastructure and configures decimal conversion for cross-chain transfers.
|
|
222
|
-
/// The `shared_decimals` parameter defines the common decimal precision used across all chains,
|
|
223
|
-
/// enabling consistent token amounts regardless of each chain's native token decimals.
|
|
224
|
-
///
|
|
225
|
-
/// # Arguments
|
|
226
|
-
/// * `owner` - The address that will own this OFT contract
|
|
227
|
-
/// * `token` - The underlying token contract address (must implement SEP-41 token interface)
|
|
228
|
-
/// * `endpoint` - The LayerZero endpoint address for cross-chain messaging
|
|
229
|
-
/// * `delegate` - Optional delegate address for endpoint configuration permissions
|
|
230
|
-
/// * `shared_decimals` - The shared decimal precision for cross-chain compatibility (must be <= local decimals)
|
|
496
|
+
/// Implements `LzReceiveInternal` for an OFT contract using the default OFT receive logic.
|
|
231
497
|
///
|
|
232
|
-
///
|
|
233
|
-
///
|
|
234
|
-
|
|
235
|
-
env: &Env,
|
|
236
|
-
owner: &Address,
|
|
237
|
-
token: &Address,
|
|
238
|
-
endpoint: &Address,
|
|
239
|
-
delegate: &Option<Address>,
|
|
240
|
-
shared_decimals: u32,
|
|
241
|
-
) {
|
|
242
|
-
// Initialize OApp (includes owner initialization)
|
|
243
|
-
initialize_oapp::<T>(env, owner, endpoint, delegate);
|
|
244
|
-
|
|
245
|
-
let local_decimals = TokenClient::new(env, token).decimals();
|
|
246
|
-
assert_with_error!(env, local_decimals >= shared_decimals, OFTError::InvalidLocalDecimals);
|
|
247
|
-
|
|
248
|
-
// Initialize OFT storage
|
|
249
|
-
OFTStorage::set_token(env, token);
|
|
250
|
-
OFTStorage::set_decimal_conversion_rate(env, &10_i128.pow(local_decimals - shared_decimals));
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// ===========================================================================
|
|
254
|
-
// Implementation Functions
|
|
255
|
-
// ===========================================================================
|
|
256
|
-
|
|
257
|
-
/// Simulates a debit operation without executing, used for quoting.
|
|
498
|
+
/// This macro generates the boilerplate `LzReceiveInternal` implementation that delegates
|
|
499
|
+
/// to `OFTInternal::__receive`, which handles decoding the OFT message, crediting
|
|
500
|
+
/// tokens to the recipient, and optionally queuing compose messages.
|
|
258
501
|
///
|
|
259
|
-
/// #
|
|
260
|
-
/// * `amount_ld` - The amount of tokens to send in local decimals
|
|
261
|
-
/// * `min_amount_ld` - The minimum amount to send in local decimals (slippage protection)
|
|
262
|
-
/// * `dst_eid` - The destination chain ID (unused in default implementation)
|
|
502
|
+
/// # Usage
|
|
263
503
|
///
|
|
264
|
-
///
|
|
265
|
-
///
|
|
266
|
-
pub fn debit_view(env: &Env, amount_ld: i128, min_amount_ld: i128, _dst_eid: u32) -> OFTReceipt {
|
|
267
|
-
let conversion_rate = decimal_conversion_rate(env);
|
|
268
|
-
let amount_sent_ld = oft_utils::remove_dust(amount_ld, conversion_rate);
|
|
269
|
-
let amount_received_ld = amount_sent_ld;
|
|
270
|
-
|
|
271
|
-
assert_with_error!(env, amount_received_ld >= min_amount_ld, OFTError::SlippageExceeded);
|
|
272
|
-
|
|
273
|
-
OFTReceipt { amount_sent_ld, amount_received_ld }
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/// Builds the OFT message payload and combines enforced options for cross-chain transfer.
|
|
277
|
-
///
|
|
278
|
-
/// # Arguments
|
|
279
|
-
/// * `from` - The address initiating the transfer
|
|
280
|
-
/// * `send_param` - The send parameters including destination, recipient, and options
|
|
281
|
-
/// * `receive_amount_ld` - The amount to be received in local decimals (after dust removal)
|
|
282
|
-
///
|
|
283
|
-
/// # Returns
|
|
284
|
-
/// A tuple of (encoded message, combined options)
|
|
285
|
-
pub fn build_msg_and_options<T: OAppOptionsType3>(
|
|
286
|
-
env: &Env,
|
|
287
|
-
from: &Address,
|
|
288
|
-
send_param: &SendParam,
|
|
289
|
-
receive_amount_ld: i128,
|
|
290
|
-
) -> (Bytes, Bytes) {
|
|
291
|
-
let has_compose = !send_param.compose_msg.is_empty();
|
|
292
|
-
let conversion_rate = decimal_conversion_rate(env);
|
|
293
|
-
let (msg, _) = OFTMessage {
|
|
294
|
-
send_to: send_param.to.clone(),
|
|
295
|
-
amount_sd: oft_utils::to_sd(env, receive_amount_ld, conversion_rate),
|
|
296
|
-
compose_from: if has_compose { Some(oft_utils::address_payload(from)) } else { None },
|
|
297
|
-
compose_msg: if has_compose { Some(send_param.compose_msg.clone()) } else { None },
|
|
298
|
-
}
|
|
299
|
-
.encode(env);
|
|
300
|
-
let msg_type = if has_compose { types::SEND_AND_CALL } else { types::SEND };
|
|
301
|
-
|
|
302
|
-
(msg, T::combine_options(env, send_param.dst_eid, msg_type, &send_param.extra_options))
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/// Quotes an OFT transfer without executing.
|
|
306
|
-
///
|
|
307
|
-
/// # Arguments
|
|
308
|
-
/// * `send_param` - The send parameters to quote
|
|
309
|
-
///
|
|
310
|
-
/// # Returns
|
|
311
|
-
/// A tuple of (transfer limits, fee details, estimated receipt)
|
|
312
|
-
pub fn quote_oft<T: OFTInternal>(env: &Env, send_param: &SendParam) -> (OFTLimit, Vec<OFTFeeDetail>, OFTReceipt) {
|
|
313
|
-
let limit = OFTLimit { min_amount_ld: 0, max_amount_ld: i128::MAX }; // No limits in default implementation
|
|
314
|
-
let fee_details = vec![env]; // No fee details in default implementation
|
|
315
|
-
let oft_receipt = T::__debit_view(env, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
316
|
-
(limit, fee_details, oft_receipt)
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/// Quotes the LayerZero messaging fee for a send operation.
|
|
320
|
-
///
|
|
321
|
-
/// # Arguments
|
|
322
|
-
/// * `from` - The address initiating the transfer
|
|
323
|
-
/// * `send_param` - The send parameters to quote
|
|
324
|
-
/// * `pay_in_zro` - Whether to pay the fee in ZRO token
|
|
325
|
-
///
|
|
326
|
-
/// # Returns
|
|
327
|
-
/// The messaging fee required for the transfer
|
|
328
|
-
pub fn quote_send<T: OFTCore>(env: &Env, from: &Address, send_param: &SendParam, pay_in_zro: bool) -> MessagingFee {
|
|
329
|
-
let OFTReceipt { amount_received_ld, .. } =
|
|
330
|
-
T::__debit_view(env, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
331
|
-
|
|
332
|
-
let (msg, options) = build_msg_and_options::<T>(env, from, send_param, amount_received_ld);
|
|
333
|
-
T::__quote(env, send_param.dst_eid, &msg, &options, pay_in_zro)
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/// Executes a cross-chain token transfer via LayerZero.
|
|
337
|
-
///
|
|
338
|
-
/// Debits tokens from the `from` address, builds the message, and sends via the endpoint.
|
|
339
|
-
/// The `from` address must be authenticated.
|
|
340
|
-
///
|
|
341
|
-
/// # Arguments
|
|
342
|
-
/// * `from` - The address sending tokens (must authorize)
|
|
343
|
-
/// * `send_param` - The send parameters (destination, recipient, amount, options)
|
|
344
|
-
/// * `fee` - The messaging fee to pay
|
|
345
|
-
/// * `refund_address` - The address to refund excess fees to
|
|
504
|
+
/// ```ignore
|
|
505
|
+
/// use oft_core::impl_oft_lz_receive;
|
|
346
506
|
///
|
|
347
|
-
/// #
|
|
348
|
-
///
|
|
349
|
-
pub fn send<T: OFTCore>(
|
|
350
|
-
env: &Env,
|
|
351
|
-
from: &Address,
|
|
352
|
-
send_param: &SendParam,
|
|
353
|
-
fee: &MessagingFee,
|
|
354
|
-
refund_address: &Address,
|
|
355
|
-
) -> (MessagingReceipt, OFTReceipt) {
|
|
356
|
-
from.require_auth();
|
|
357
|
-
|
|
358
|
-
let oft_receipt = T::__debit(env, from, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
359
|
-
|
|
360
|
-
let (msg, options) = build_msg_and_options::<T>(env, from, send_param, oft_receipt.amount_received_ld);
|
|
361
|
-
let msg_receipt = T::__lz_send(env, send_param.dst_eid, &msg, &options, from, fee, refund_address);
|
|
362
|
-
|
|
363
|
-
OFTSent {
|
|
364
|
-
guid: msg_receipt.guid.clone(),
|
|
365
|
-
dst_eid: send_param.dst_eid,
|
|
366
|
-
from: from.clone(),
|
|
367
|
-
amount_sent_ld: oft_receipt.amount_sent_ld,
|
|
368
|
-
amount_received_ld: oft_receipt.amount_received_ld,
|
|
369
|
-
}
|
|
370
|
-
.publish(env);
|
|
371
|
-
|
|
372
|
-
(msg_receipt, oft_receipt)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/// Retrieves the decimal conversion rate used for cross-chain normalization.
|
|
376
|
-
pub fn decimal_conversion_rate(env: &Env) -> i128 {
|
|
377
|
-
OFTStorage::decimal_conversion_rate(env).unwrap_or_panic(env, OFTError::NotInitialized)
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/// Retrieves the token address associated with this OFT.
|
|
381
|
-
pub fn token(env: &Env) -> Address {
|
|
382
|
-
OFTStorage::token(env).unwrap_or_panic(env, OFTError::NotInitialized)
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
/// Retrieves the shared decimals used for cross-chain normalization.
|
|
386
|
-
pub fn shared_decimals(env: &Env) -> u32 {
|
|
387
|
-
let token = token(env);
|
|
388
|
-
let local_decimals = TokenClient::new(env, &token).decimals();
|
|
389
|
-
let conversion_rate = decimal_conversion_rate(env);
|
|
390
|
-
local_decimals - conversion_rate.ilog10()
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// ===========================================================================
|
|
394
|
-
// LzReceive Handler (called by OAppReceiver)
|
|
395
|
-
// ===========================================================================
|
|
396
|
-
|
|
397
|
-
/// Handles incoming cross-chain OFT transfer from LayerZero endpoint.
|
|
507
|
+
/// #[oapp]
|
|
508
|
+
/// pub struct MyOFT;
|
|
398
509
|
///
|
|
399
|
-
///
|
|
510
|
+
/// impl OFTInternal for MyOFT {
|
|
511
|
+
/// // ... implement __debit and __credit ...
|
|
512
|
+
/// }
|
|
400
513
|
///
|
|
401
|
-
///
|
|
402
|
-
///
|
|
403
|
-
///
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
let conversion_rate = decimal_conversion_rate(env);
|
|
421
|
-
let amount_received_ld =
|
|
422
|
-
T::__credit(env, &send_to, oft_utils::to_ld(oft_msg.amount_sd, conversion_rate), origin.src_eid);
|
|
423
|
-
|
|
424
|
-
if oft_msg.is_composed() {
|
|
425
|
-
let compose_msg = OFTComposeMsg {
|
|
426
|
-
nonce: origin.nonce,
|
|
427
|
-
src_eid: origin.src_eid,
|
|
428
|
-
amount_ld: amount_received_ld,
|
|
429
|
-
compose_from: oft_msg.compose_from.unwrap(),
|
|
430
|
-
compose_msg: oft_msg.compose_msg.unwrap(),
|
|
514
|
+
/// // Instead of manually implementing LzReceiveInternal:
|
|
515
|
+
/// impl_oft_lz_receive!(MyOFT);
|
|
516
|
+
/// ```
|
|
517
|
+
#[macro_export]
|
|
518
|
+
macro_rules! impl_oft_lz_receive {
|
|
519
|
+
($contract:ty) => {
|
|
520
|
+
impl oapp::oapp_receiver::LzReceiveInternal for $contract {
|
|
521
|
+
fn __lz_receive(
|
|
522
|
+
env: &soroban_sdk::Env,
|
|
523
|
+
origin: &endpoint_v2::Origin,
|
|
524
|
+
guid: &soroban_sdk::BytesN<32>,
|
|
525
|
+
message: &soroban_sdk::Bytes,
|
|
526
|
+
extra_data: &soroban_sdk::Bytes,
|
|
527
|
+
executor: &soroban_sdk::Address,
|
|
528
|
+
value: i128,
|
|
529
|
+
) {
|
|
530
|
+
<Self as oft_core::OFTInternal>::__receive(env, origin, guid, message, extra_data, executor, value)
|
|
531
|
+
}
|
|
431
532
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
let endpoint_client = MessagingComposerClient::new(env, &T::endpoint(env));
|
|
435
|
-
endpoint_client.send_compose(&env.current_contract_address(), &send_to, guid, &0, &compose_msg);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
events::OFTReceived { guid: guid.clone(), src_eid: origin.src_eid, to: send_to, amount_received_ld }.publish(env);
|
|
533
|
+
};
|
|
439
534
|
}
|