@layerzerolabs/protocol-stellar-v2 0.2.29 → 0.2.30
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 +371 -321
- package/.turbo/turbo-lint.log +211 -202
- package/.turbo/turbo-test.log +1766 -1673
- package/Cargo.lock +11 -1
- package/contracts/common-macros/src/lib.rs +0 -2
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +1 -0
- package/contracts/endpoint-v2/src/messaging_channel.rs +32 -3
- package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +1 -1
- package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +1 -1
- package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +6 -6
- package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_payload_hash.rs +1 -1
- package/contracts/endpoint-v2/src/tests/messaging_channel/outbound.rs +16 -10
- package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +10 -10
- package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +3 -3
- package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +4 -3
- package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +1 -57
- package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_missing_internal.stderr +0 -30
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -3
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +6 -4
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -3
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -3
- package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_auth_trait.stderr +0 -30
- package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_upgradeable_internal.stderr +0 -30
- package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/basic.rs +0 -2
- package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/multisig_contract.rs +0 -2
- package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/no_migration.rs +0 -2
- package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/no_user_contractimpl.rs +1 -3
- package/contracts/message-libs/message-lib-common/src/packet_codec_v1.rs +3 -6
- package/contracts/message-libs/message-lib-common/src/tests/worker_options/extract_type_3_options.rs +10 -0
- package/contracts/message-libs/message-lib-common/src/worker_options.rs +6 -2
- package/contracts/message-libs/treasury/src/interfaces/zro_fee_lib.rs +3 -3
- package/contracts/message-libs/treasury/src/lib.rs +2 -1
- package/contracts/message-libs/treasury/src/tests/setup.rs +1 -1
- package/contracts/message-libs/treasury/src/treasury.rs +5 -2
- package/contracts/message-libs/uln-302/src/errors.rs +2 -0
- package/contracts/message-libs/uln-302/src/events.rs +3 -3
- package/contracts/message-libs/uln-302/src/interfaces/receive_uln.rs +8 -0
- package/contracts/message-libs/uln-302/src/lib.rs +2 -1
- package/contracts/message-libs/uln-302/src/receive_uln.rs +16 -13
- package/contracts/message-libs/uln-302/src/send_uln.rs +51 -24
- package/contracts/message-libs/uln-302/src/storage.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +45 -1
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/verifiable.rs +63 -0
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +47 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +50 -1
- package/contracts/message-libs/uln-302/src/uln302.rs +0 -8
- package/contracts/oapps/counter/Cargo.toml +4 -4
- package/contracts/oapps/counter/integration_tests/setup_uln.rs +22 -2
- package/contracts/oapps/counter/src/counter.rs +8 -8
- package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +33 -10
- package/contracts/oapps/oapp/src/lib.rs +6 -2
- package/contracts/oapps/oapp/src/oapp_core.rs +49 -24
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +21 -14
- package/contracts/oapps/oapp/src/oapp_receiver.rs +17 -16
- package/contracts/oapps/oapp/src/oapp_sender.rs +66 -15
- package/contracts/oapps/oapp/src/tests/oapp_core.rs +5 -5
- package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +18 -18
- package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +4 -4
- package/contracts/oapps/oapp/src/tests/oapp_sender.rs +3 -3
- package/contracts/oapps/oapp-macros/Cargo.toml +0 -1
- package/contracts/oapps/oapp-macros/src/generators.rs +87 -46
- package/contracts/oapps/oapp-macros/src/lib.rs +3 -61
- package/contracts/oapps/oapp-macros/src/tests/oapp.rs +9 -23
- package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +15 -11
- package/contracts/oapps/oft/Cargo.toml +1 -1
- package/contracts/oapps/oft/integration-tests/extensions/test_oft_fee.rs +3 -3
- package/contracts/oapps/oft/integration-tests/extensions/test_pausable.rs +4 -4
- package/contracts/oapps/oft/integration-tests/extensions/test_rate_limiter.rs +144 -8
- package/contracts/oapps/oft/integration-tests/setup.rs +4 -2
- package/contracts/oapps/oft/integration-tests/utils.rs +25 -11
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +65 -63
- package/contracts/oapps/oft/src/extensions/pausable.rs +2 -3
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +22 -5
- package/contracts/oapps/oft/src/interfaces/mint_burnable.rs +18 -0
- package/contracts/oapps/oft/src/interfaces/mod.rs +3 -0
- package/contracts/oapps/oft/src/lib.rs +4 -2
- package/contracts/oapps/oft/src/oft.rs +35 -36
- package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +13 -9
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +14 -9
- package/contracts/oapps/oft/src/oft_types/mod.rs +14 -12
- package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +28 -20
- package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +136 -2
- package/contracts/oapps/oft/src/tests/oft_types/lock_unlock.rs +12 -8
- package/contracts/oapps/oft-core/integration-tests/setup.rs +8 -9
- package/contracts/oapps/oft-core/integration-tests/test_with_sml.rs +7 -6
- package/contracts/oapps/oft-core/integration-tests/utils.rs +5 -4
- package/contracts/oapps/oft-core/src/codec/oft_compose_msg_codec.rs +2 -2
- package/contracts/oapps/oft-core/src/codec/oft_msg_codec.rs +33 -37
- package/contracts/oapps/oft-core/src/errors.rs +2 -1
- package/contracts/oapps/oft-core/src/events.rs +6 -0
- package/contracts/oapps/oft-core/src/lib.rs +8 -4
- package/contracts/oapps/oft-core/src/oft_core.rs +205 -148
- package/contracts/oapps/oft-core/src/storage.rs +4 -2
- package/contracts/oapps/oft-core/src/tests/test_decimals.rs +2 -2
- package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +6 -6
- package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +7 -6
- package/contracts/oapps/oft-core/src/tests/test_oft_msg_codec.rs +11 -82
- package/contracts/oapps/oft-core/src/tests/test_quote_oft.rs +13 -13
- package/contracts/oapps/oft-core/src/tests/test_quote_send.rs +1 -1
- package/contracts/oapps/oft-core/src/tests/test_resolve_address.rs +2 -2
- package/contracts/oapps/oft-core/src/tests/test_send.rs +22 -22
- package/contracts/oapps/oft-core/src/tests/test_utils.rs +20 -22
- package/contracts/oapps/oft-core/src/utils.rs +12 -8
- package/contracts/sac-manager/Cargo.toml +25 -0
- package/contracts/sac-manager/src/errors.rs +18 -0
- package/contracts/sac-manager/src/extensions/mod.rs +6 -0
- package/contracts/sac-manager/src/extensions/redistribution.rs +109 -0
- package/contracts/sac-manager/src/extensions/supply_control/mod.rs +488 -0
- package/contracts/sac-manager/src/extensions/supply_control/rate_limit.rs +126 -0
- package/contracts/sac-manager/src/interfaces/mod.rs +3 -0
- package/contracts/sac-manager/src/interfaces/sac_manager.rs +52 -0
- package/contracts/sac-manager/src/lib.rs +23 -0
- package/contracts/sac-manager/src/sac_manager.rs +193 -0
- package/contracts/sac-manager/src/storage.rs +20 -0
- package/contracts/sac-manager/src/tests/mod.rs +14 -0
- package/contracts/sac-manager/src/tests/redistribution/mod.rs +1 -0
- package/contracts/sac-manager/src/tests/redistribution/redistribute_funds.rs +82 -0
- package/contracts/sac-manager/src/tests/sac_manager/admin_mint.rs +206 -0
- package/contracts/sac-manager/src/tests/sac_manager/burn.rs +215 -0
- package/contracts/sac-manager/src/tests/sac_manager/clawback.rs +209 -0
- package/contracts/sac-manager/src/tests/sac_manager/mint.rs +252 -0
- package/contracts/sac-manager/src/tests/sac_manager/mod.rs +9 -0
- package/contracts/sac-manager/src/tests/sac_manager/set_admin.rs +36 -0
- package/contracts/sac-manager/src/tests/sac_manager/set_authorized.rs +43 -0
- package/contracts/sac-manager/src/tests/sac_manager/set_oft_address.rs +47 -0
- package/contracts/sac-manager/src/tests/sac_manager/test_helper.rs +75 -0
- package/contracts/sac-manager/src/tests/sac_manager/view_functions.rs +60 -0
- package/contracts/sac-manager/src/tests/supply_control/enumerable_set.rs +256 -0
- package/contracts/sac-manager/src/tests/supply_control/mod.rs +8 -0
- package/contracts/sac-manager/src/tests/supply_control/refill.rs +90 -0
- package/contracts/sac-manager/src/tests/supply_control/set_mint_whitelist.rs +245 -0
- package/contracts/sac-manager/src/tests/supply_control/set_supply_controller.rs +267 -0
- package/contracts/sac-manager/src/tests/supply_control/set_supply_controller_manager.rs +122 -0
- package/contracts/sac-manager/src/tests/supply_control/test_helper.rs +38 -0
- package/contracts/sac-manager/src/tests/supply_control/update_allow_any_mint_burn.rs +114 -0
- package/contracts/sac-manager/src/tests/supply_control/update_limit_config.rs +257 -0
- package/contracts/sac-manager/src/tests/test_helper.rs +190 -0
- package/contracts/upgrader/src/lib.rs +2 -1
- package/contracts/utils/src/errors.rs +0 -1
- package/contracts/utils/src/tests/upgradeable.rs +0 -66
- package/contracts/utils/src/upgradeable.rs +0 -18
- package/contracts/workers/dvn/src/dvn.rs +2 -2
- package/contracts/workers/dvn/src/interfaces/dvn.rs +2 -2
- package/contracts/workers/dvn/src/lib.rs +2 -1
- package/contracts/workers/dvn-fee-lib/src/lib.rs +3 -1
- package/contracts/workers/executor/src/auth.rs +42 -26
- package/contracts/workers/executor/src/executor.rs +28 -3
- package/contracts/workers/executor/src/lib.rs +4 -2
- package/contracts/workers/executor/src/storage.rs +21 -1
- package/contracts/workers/executor/src/tests/auth.rs +64 -20
- package/contracts/workers/executor/src/tests/executor.rs +1 -1
- package/contracts/workers/executor/src/tests/setup.rs +18 -0
- package/contracts/workers/executor-fee-lib/src/lib.rs +4 -1
- package/contracts/workers/executor-helper/src/executor_helper.rs +24 -10
- package/contracts/workers/executor-helper/src/tests/setup.rs +147 -34
- package/contracts/workers/price-feed/src/lib.rs +3 -1
- package/contracts/workers/worker/src/lib.rs +2 -1
- package/contracts/workers/worker/src/worker.rs +31 -17
- package/docs/oapp-guide.md +17 -8
- package/docs/oft-guide.md +3 -3
- package/package.json +3 -3
- package/sdk/.turbo/turbo-test.log +512 -351
- package/sdk/dist/generated/bml.d.ts +3 -9
- package/sdk/dist/generated/bml.js +6 -7
- package/sdk/dist/generated/counter.d.ts +22 -28
- package/sdk/dist/generated/counter.js +11 -12
- package/sdk/dist/generated/dvn.d.ts +36 -54
- package/sdk/dist/generated/dvn.js +10 -15
- package/sdk/dist/generated/dvn_fee_lib.d.ts +3 -21
- package/sdk/dist/generated/dvn_fee_lib.js +6 -11
- package/sdk/dist/generated/endpoint.d.ts +3 -9
- package/sdk/dist/generated/endpoint.js +6 -7
- package/sdk/dist/generated/executor.d.ts +80 -54
- package/sdk/dist/generated/executor.js +16 -16
- package/sdk/dist/generated/executor_fee_lib.d.ts +3 -21
- package/sdk/dist/generated/executor_fee_lib.js +6 -11
- package/sdk/dist/generated/executor_helper.d.ts +36 -42
- package/sdk/dist/generated/executor_helper.js +9 -10
- package/sdk/dist/generated/layerzero_view.d.ts +20 -32
- package/sdk/dist/generated/layerzero_view.js +25 -26
- package/sdk/dist/generated/oft.d.ts +147 -79
- package/sdk/dist/generated/oft.js +47 -54
- package/sdk/dist/generated/price_feed.d.ts +20 -38
- package/sdk/dist/generated/price_feed.js +15 -20
- package/sdk/dist/generated/sac_manager.d.ts +1309 -0
- package/sdk/dist/generated/sac_manager.js +484 -0
- package/sdk/dist/generated/sml.d.ts +3 -9
- package/sdk/dist/generated/sml.js +6 -7
- package/sdk/dist/generated/treasury.d.ts +3 -9
- package/sdk/dist/generated/treasury.js +8 -9
- package/sdk/dist/generated/uln302.d.ts +20 -20
- package/sdk/dist/generated/uln302.js +25 -22
- package/sdk/dist/generated/upgrader.d.ts +3 -9
- package/sdk/dist/generated/upgrader.js +6 -7
- package/sdk/dist/index.d.ts +1 -0
- package/sdk/dist/index.js +1 -0
- package/sdk/package.json +1 -1
- package/sdk/src/index.ts +1 -0
- package/sdk/test/oft-sml.test.ts +7 -5
- package/sdk/test/sac-manager-redistribution.test.ts +578 -0
- package/sdk/test/suites/globalSetup.ts +11 -6
- package/sdk/test/test_data/test_upgradeable_dvn.wasm +0 -0
- package/sdk/test/upgrader.test.ts +75 -202
- package/sdk/test/utils.ts +40 -0
- package/tools/ts-bindings-gen/src/main.rs +1 -0
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
//!
|
|
17
17
|
//! #[contractimpl]
|
|
18
18
|
//! impl MyOFT {
|
|
19
|
-
//! pub fn __constructor(env: &Env, token: &Address, owner: &Address, endpoint: &Address, delegate: &
|
|
20
|
-
//! Self::__initialize_oft(env,
|
|
19
|
+
//! pub fn __constructor(env: &Env, token: &Address, owner: &Address, endpoint: &Address, delegate: &Address) {
|
|
20
|
+
//! Self::__initialize_oft(env, token, 6, owner, endpoint, delegate)
|
|
21
21
|
//! }
|
|
22
22
|
//! }
|
|
23
23
|
//!
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
//! // Internal methods - NOT exposed as contract entrypoints
|
|
29
29
|
//! // IMPORTANT: Do NOT use #[contractimpl] here to keep methods internal
|
|
30
30
|
//! impl OFTInternal for MyOFT {
|
|
31
|
-
//! fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) ->
|
|
31
|
+
//! fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> (i128, i128) {
|
|
32
32
|
//! // Your debit logic (e.g., burn or lock tokens)
|
|
33
33
|
//! oft_core::oft_types::mint_burn::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid)
|
|
34
34
|
//! }
|
|
@@ -45,21 +45,24 @@
|
|
|
45
45
|
|
|
46
46
|
use crate::{
|
|
47
47
|
self as oft_core,
|
|
48
|
-
codec::{
|
|
48
|
+
codec::{
|
|
49
|
+
oft_compose_msg_codec::OFTComposeMsg,
|
|
50
|
+
oft_msg_codec::{ComposeData, OFTMessage},
|
|
51
|
+
},
|
|
49
52
|
errors::OFTError,
|
|
50
53
|
events::{self, MsgInspectorSet, OFTSent},
|
|
51
54
|
storage::OFTStorage,
|
|
52
|
-
types::{
|
|
55
|
+
types::{OFTFeeDetail, OFTLimit, OFTReceipt, SendParam, SEND, SEND_AND_CALL},
|
|
53
56
|
utils as oft_utils,
|
|
54
57
|
};
|
|
55
58
|
use common_macros::{contract_trait, only_auth};
|
|
56
59
|
use endpoint_v2::{MessagingComposerClient, MessagingFee, MessagingReceipt};
|
|
57
60
|
use oapp::{
|
|
58
|
-
|
|
59
|
-
oapp_core::{initialize_oapp, OAppCore},
|
|
61
|
+
oapp_core::initialize_oapp,
|
|
60
62
|
oapp_options_type3::OAppOptionsType3,
|
|
61
63
|
oapp_receiver::OAppReceiver,
|
|
62
|
-
oapp_sender::OAppSenderInternal,
|
|
64
|
+
oapp_sender::{FeePayer, OAppSenderInternal},
|
|
65
|
+
OAppMsgInspectorClient,
|
|
63
66
|
};
|
|
64
67
|
use soroban_sdk::{assert_with_error, token::TokenClient, vec, Address, Bytes, Env, Vec};
|
|
65
68
|
use utils::{option_ext::OptionExt, ownable::OwnableInitializer};
|
|
@@ -84,7 +87,7 @@ use utils::{option_ext::OptionExt, ownable::OwnableInitializer};
|
|
|
84
87
|
///
|
|
85
88
|
/// This trait extends all OApp supertraits and contains both the token operations
|
|
86
89
|
/// and the internal sending logic. `OFTCore` serves only as an entrypoint wrapper.
|
|
87
|
-
pub trait OFTInternal:
|
|
90
|
+
pub trait OFTInternal: OAppReceiver + OAppSenderInternal + OAppOptionsType3 + OwnableInitializer {
|
|
88
91
|
// =========================================================================
|
|
89
92
|
// Initialization
|
|
90
93
|
// =========================================================================
|
|
@@ -96,21 +99,21 @@ pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOption
|
|
|
96
99
|
/// enabling consistent token amounts regardless of each chain's native token decimals.
|
|
97
100
|
///
|
|
98
101
|
/// # Arguments
|
|
99
|
-
/// * `owner` - The address that will own this OFT contract
|
|
100
102
|
/// * `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
103
|
/// * `shared_decimals` - The shared decimal precision for cross-chain compatibility (must be <= local decimals)
|
|
104
|
+
/// * `owner` - The address that will own this OFT contract
|
|
105
|
+
/// * `endpoint` - The LayerZero endpoint address for cross-chain messaging
|
|
106
|
+
/// * `delegate` - The delegate address for endpoint configuration permissions
|
|
104
107
|
///
|
|
105
108
|
/// # Panics
|
|
106
109
|
/// * `OFTError::InvalidLocalDecimals` - If the token's local decimals are less than `shared_decimals`
|
|
107
110
|
fn __initialize_oft(
|
|
108
111
|
env: &Env,
|
|
109
|
-
owner: &Address,
|
|
110
112
|
token: &Address,
|
|
111
|
-
endpoint: &Address,
|
|
112
|
-
delegate: &Option<Address>,
|
|
113
113
|
shared_decimals: u32,
|
|
114
|
+
owner: &Address,
|
|
115
|
+
endpoint: &Address,
|
|
116
|
+
delegate: &Address,
|
|
114
117
|
) {
|
|
115
118
|
// Initialize OApp (includes owner initialization)
|
|
116
119
|
initialize_oapp::<Self>(env, owner, endpoint, delegate);
|
|
@@ -136,8 +139,9 @@ pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOption
|
|
|
136
139
|
/// * `dst_eid` - The destination chain ID
|
|
137
140
|
///
|
|
138
141
|
/// # Returns
|
|
139
|
-
/// `
|
|
140
|
-
|
|
142
|
+
/// * `amount_sent_ld` - The amount sent in local decimals
|
|
143
|
+
/// * `amount_received_ld` - The amount received in local decimals on the remote
|
|
144
|
+
fn __debit(env: &Env, from: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> (i128, i128);
|
|
141
145
|
|
|
142
146
|
/// Credits tokens to recipient after receiving cross-chain transfer.
|
|
143
147
|
///
|
|
@@ -156,59 +160,33 @@ pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOption
|
|
|
156
160
|
|
|
157
161
|
// ----- Quote Methods -----
|
|
158
162
|
|
|
159
|
-
/// Quotes an OFT transfer without executing.
|
|
160
|
-
|
|
161
|
-
|
|
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);
|
|
163
|
+
/// Quotes an OFT transfer without executing. Returns (limits, fee details, receipt).
|
|
164
|
+
fn __quote_oft(env: &Env, _from: &Address, send_param: &SendParam) -> (OFTLimit, Vec<OFTFeeDetail>, OFTReceipt) {
|
|
165
|
+
assert_nonnegative_amount(env, send_param);
|
|
171
166
|
|
|
172
|
-
let limit = OFTLimit { min_amount_ld: 0, max_amount_ld:
|
|
167
|
+
let limit = OFTLimit { min_amount_ld: 0, max_amount_ld: u64::MAX as i128 };
|
|
173
168
|
let fee_details = vec![env];
|
|
174
|
-
let
|
|
175
|
-
|
|
169
|
+
let (amount_sent_ld, amount_received_ld) =
|
|
170
|
+
Self::__debit_view(env, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
171
|
+
(limit, fee_details, OFTReceipt { amount_sent_ld, amount_received_ld })
|
|
176
172
|
}
|
|
177
173
|
|
|
178
|
-
/// Quotes the LayerZero messaging fee for a send
|
|
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
|
|
174
|
+
/// Quotes the LayerZero messaging fee for a send. Builds the message internally
|
|
175
|
+
/// to get an accurate fee estimate from the endpoint.
|
|
187
176
|
fn __quote_send(env: &Env, from: &Address, send_param: &SendParam, pay_in_zro: bool) -> MessagingFee {
|
|
188
|
-
|
|
177
|
+
assert_nonnegative_amount(env, send_param);
|
|
189
178
|
|
|
190
|
-
let
|
|
179
|
+
let (_amount_sent_ld, amount_received_ld) =
|
|
191
180
|
Self::__debit_view(env, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
192
181
|
|
|
193
|
-
let (
|
|
194
|
-
Self::__quote(env, send_param.dst_eid, &
|
|
182
|
+
let (message, options) = Self::__build_msg_and_options(env, from, send_param, amount_received_ld);
|
|
183
|
+
Self::__quote(env, send_param.dst_eid, &message, &options, pay_in_zro)
|
|
195
184
|
}
|
|
196
185
|
|
|
197
186
|
// ----- Send Method -----
|
|
198
187
|
|
|
199
|
-
/// Executes a cross-chain token transfer
|
|
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)
|
|
188
|
+
/// Executes a cross-chain token transfer: debits `from`, builds the OFT message,
|
|
189
|
+
/// and dispatches it via the LayerZero endpoint.
|
|
212
190
|
fn __send(
|
|
213
191
|
env: &Env,
|
|
214
192
|
from: &Address,
|
|
@@ -218,89 +196,85 @@ pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOption
|
|
|
218
196
|
) -> (MessagingReceipt, OFTReceipt) {
|
|
219
197
|
from.require_auth();
|
|
220
198
|
|
|
221
|
-
|
|
199
|
+
assert_nonnegative_amount(env, send_param);
|
|
222
200
|
|
|
223
|
-
let
|
|
201
|
+
let (amount_sent_ld, amount_received_ld) =
|
|
202
|
+
Self::__debit(env, from, send_param.amount_ld, send_param.min_amount_ld, send_param.dst_eid);
|
|
224
203
|
|
|
225
|
-
let (
|
|
226
|
-
let
|
|
204
|
+
let (message, options) = Self::__build_msg_and_options(env, from, send_param, amount_received_ld);
|
|
205
|
+
let messaging_receipt = Self::__lz_send(
|
|
206
|
+
env,
|
|
207
|
+
send_param.dst_eid,
|
|
208
|
+
&message,
|
|
209
|
+
&options,
|
|
210
|
+
&FeePayer::Verified(from.clone()),
|
|
211
|
+
fee,
|
|
212
|
+
refund_address,
|
|
213
|
+
);
|
|
227
214
|
|
|
228
215
|
OFTSent {
|
|
229
|
-
guid:
|
|
216
|
+
guid: messaging_receipt.guid.clone(),
|
|
230
217
|
dst_eid: send_param.dst_eid,
|
|
231
218
|
from: from.clone(),
|
|
232
|
-
amount_sent_ld
|
|
233
|
-
amount_received_ld
|
|
219
|
+
amount_sent_ld,
|
|
220
|
+
amount_received_ld,
|
|
234
221
|
}
|
|
235
222
|
.publish(env);
|
|
236
223
|
|
|
237
|
-
(
|
|
224
|
+
(messaging_receipt, OFTReceipt { amount_sent_ld, amount_received_ld })
|
|
238
225
|
}
|
|
239
226
|
|
|
240
227
|
// ----- View/Helper Methods -----
|
|
241
228
|
|
|
242
|
-
/// Simulates a debit
|
|
243
|
-
///
|
|
244
|
-
///
|
|
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)
|
|
229
|
+
/// Simulates a debit for quoting — removes dust but charges no fee by default.
|
|
230
|
+
/// Override to add custom fee logic. Panics with `SlippageExceeded` if the
|
|
231
|
+
/// resulting amount is below `min_amount_ld`.
|
|
252
232
|
///
|
|
253
233
|
/// # Returns
|
|
254
|
-
/// `
|
|
255
|
-
///
|
|
256
|
-
|
|
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 {
|
|
234
|
+
/// * `amount_sent_ld` - The amount sent in local decimals
|
|
235
|
+
/// * `amount_received_ld` - The amount received in local decimals on the remote
|
|
236
|
+
fn __debit_view(env: &Env, amount_ld: i128, min_amount_ld: i128, _dst_eid: u32) -> (i128, i128) {
|
|
259
237
|
let conversion_rate = Self::__decimal_conversion_rate(env);
|
|
260
238
|
let amount_sent_ld = oft_utils::remove_dust(amount_ld, conversion_rate);
|
|
261
239
|
let amount_received_ld = amount_sent_ld;
|
|
262
240
|
|
|
263
241
|
assert_with_error!(env, amount_received_ld >= min_amount_ld, OFTError::SlippageExceeded);
|
|
264
242
|
|
|
265
|
-
|
|
243
|
+
(amount_sent_ld, amount_received_ld)
|
|
266
244
|
}
|
|
267
245
|
|
|
268
|
-
///
|
|
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)
|
|
246
|
+
/// Encodes the OFT message payload and merges enforced + extra options.
|
|
247
|
+
/// Runs the message inspector (if set) before returning `(message, options)`.
|
|
280
248
|
fn __build_msg_and_options(
|
|
281
249
|
env: &Env,
|
|
282
250
|
from: &Address,
|
|
283
251
|
send_param: &SendParam,
|
|
284
|
-
|
|
252
|
+
amount_received_ld: i128,
|
|
285
253
|
) -> (Bytes, Bytes) {
|
|
286
254
|
let has_compose = !send_param.compose_msg.is_empty();
|
|
255
|
+
let compose_data = has_compose
|
|
256
|
+
.then(|| ComposeData { from: oft_utils::address_payload(env, from), msg: send_param.compose_msg.clone() });
|
|
257
|
+
|
|
258
|
+
// Build the OFT message
|
|
287
259
|
let conversion_rate = Self::__decimal_conversion_rate(env);
|
|
288
|
-
let
|
|
260
|
+
let message = OFTMessage {
|
|
289
261
|
send_to: send_param.to.clone(),
|
|
290
|
-
amount_sd: oft_utils::to_sd(env,
|
|
291
|
-
|
|
292
|
-
compose_msg: if has_compose { Some(send_param.compose_msg.clone()) } else { None },
|
|
262
|
+
amount_sd: oft_utils::to_sd(env, amount_received_ld, conversion_rate),
|
|
263
|
+
compose: compose_data,
|
|
293
264
|
}
|
|
294
265
|
.encode(env);
|
|
295
|
-
|
|
266
|
+
|
|
267
|
+
// Combine the options with the message type
|
|
268
|
+
let msg_type = if has_compose { SEND_AND_CALL } else { SEND };
|
|
296
269
|
let options = Self::combine_options(env, send_param.dst_eid, msg_type, &send_param.extra_options);
|
|
297
270
|
|
|
298
271
|
// Optionally inspect message and options if inspector is set
|
|
272
|
+
// If it fails inspection, needs to revert in the implementation. ie. does not rely on return boolean
|
|
299
273
|
if let Some(inspector) = Self::__msg_inspector(env) {
|
|
300
|
-
OAppMsgInspectorClient::new(env, &inspector).inspect(&env.current_contract_address(), &
|
|
274
|
+
OAppMsgInspectorClient::new(env, &inspector).inspect(&env.current_contract_address(), &message, &options);
|
|
301
275
|
}
|
|
302
276
|
|
|
303
|
-
(
|
|
277
|
+
(message, options)
|
|
304
278
|
}
|
|
305
279
|
|
|
306
280
|
// ----- Storage Accessors -----
|
|
@@ -310,17 +284,20 @@ pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOption
|
|
|
310
284
|
OFTStorage::token(env).unwrap_or_panic(env, OFTError::NotInitialized)
|
|
311
285
|
}
|
|
312
286
|
|
|
287
|
+
/// Retrieves the difference between local and shared decimals (`local_decimals - shared_decimals`).
|
|
288
|
+
fn __decimals_diff(env: &Env) -> u32 {
|
|
289
|
+
OFTStorage::decimals_diff(env).unwrap_or_panic(env, OFTError::NotInitialized)
|
|
290
|
+
}
|
|
291
|
+
|
|
313
292
|
/// Retrieves the decimal conversion rate used for cross-chain normalization.
|
|
314
293
|
fn __decimal_conversion_rate(env: &Env) -> i128 {
|
|
315
|
-
|
|
316
|
-
10_i128.pow(decimals_diff)
|
|
294
|
+
10_i128.pow(Self::__decimals_diff(env))
|
|
317
295
|
}
|
|
318
296
|
|
|
319
297
|
/// Retrieves the shared decimals used for cross-chain normalization.
|
|
320
298
|
fn __shared_decimals(env: &Env) -> u32 {
|
|
321
299
|
let local_decimals = TokenClient::new(env, &Self::__token(env)).decimals();
|
|
322
|
-
|
|
323
|
-
local_decimals - decimals_diff
|
|
300
|
+
local_decimals - Self::__decimals_diff(env)
|
|
324
301
|
}
|
|
325
302
|
|
|
326
303
|
/// Returns the message inspector address if set.
|
|
@@ -329,13 +306,6 @@ pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOption
|
|
|
329
306
|
}
|
|
330
307
|
|
|
331
308
|
/// 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
309
|
fn __set_msg_inspector(env: &Env, inspector: &Option<Address>) {
|
|
340
310
|
OFTStorage::set_or_remove_msg_inspector(env, inspector);
|
|
341
311
|
MsgInspectorSet { inspector: inspector.clone() }.publish(env);
|
|
@@ -367,17 +337,19 @@ pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOption
|
|
|
367
337
|
let oft_msg = OFTMessage::decode(message);
|
|
368
338
|
let send_to = oft_utils::resolve_address(env, &oft_msg.send_to);
|
|
369
339
|
|
|
340
|
+
// Convert the amount to local decimals and credit the recipient
|
|
370
341
|
let conversion_rate = Self::__decimal_conversion_rate(env);
|
|
371
342
|
let amount_received_ld =
|
|
372
343
|
Self::__credit(env, &send_to, oft_utils::to_ld(oft_msg.amount_sd, conversion_rate), origin.src_eid);
|
|
373
344
|
|
|
374
|
-
|
|
345
|
+
// If there is a compose message, send it
|
|
346
|
+
if let Some(compose) = oft_msg.compose {
|
|
375
347
|
let compose_msg = OFTComposeMsg {
|
|
376
348
|
nonce: origin.nonce,
|
|
377
349
|
src_eid: origin.src_eid,
|
|
378
350
|
amount_ld: amount_received_ld,
|
|
379
|
-
compose_from:
|
|
380
|
-
compose_msg:
|
|
351
|
+
compose_from: compose.from,
|
|
352
|
+
compose_msg: compose.msg,
|
|
381
353
|
}
|
|
382
354
|
.encode(env);
|
|
383
355
|
|
|
@@ -394,97 +366,167 @@ pub trait OFTInternal: OAppCore + OAppReceiver + OAppSenderInternal + OAppOption
|
|
|
394
366
|
// OFTCore Trait (exposed as contract entrypoints)
|
|
395
367
|
// ===========================================================================
|
|
396
368
|
|
|
397
|
-
///
|
|
369
|
+
/// Public OFT (Omnichain Fungible Token) interface for cross-chain token transfers.
|
|
398
370
|
///
|
|
399
|
-
///
|
|
400
|
-
///
|
|
371
|
+
/// `OFTCore` defines the externally callable contract entrypoints for interacting with an
|
|
372
|
+
/// OFT deployment. Every method in this trait becomes a Soroban contract function via
|
|
373
|
+
/// `#[contract_trait]`. All business logic lives in [`OFTInternal`] — this trait is a
|
|
374
|
+
/// thin entrypoint layer that delegates to the internal implementations.
|
|
401
375
|
///
|
|
402
|
-
///
|
|
376
|
+
/// # Typical Client Workflow
|
|
377
|
+
///
|
|
378
|
+
/// 1. Call [`quote_oft`](OFTCore::quote_oft) to preview transfer limits, fees, and the
|
|
379
|
+
/// estimated receipt (amounts sent vs. received after dust removal and fees).
|
|
380
|
+
/// 2. Call [`quote_send`](OFTCore::quote_send) to obtain the LayerZero messaging fee.
|
|
381
|
+
/// 3. Call [`send`](OFTCore::send) to execute the cross-chain transfer, supplying the
|
|
382
|
+
/// quoted fee and a refund address for any excess.
|
|
403
383
|
#[contract_trait(client_name = "OFTClient")]
|
|
404
384
|
pub trait OFTCore: OFTInternal {
|
|
405
|
-
///
|
|
385
|
+
/// Returns the address of the underlying SEP-41 token managed by this OFT.
|
|
406
386
|
fn token(env: &soroban_sdk::Env) -> soroban_sdk::Address {
|
|
407
387
|
Self::__token(env)
|
|
408
388
|
}
|
|
409
389
|
|
|
410
|
-
/// Returns OFT version as (major, minor)
|
|
390
|
+
/// Returns the OFT messaging protocol version as `(major, minor)`.
|
|
391
|
+
///
|
|
392
|
+
/// The version is used by off-chain tooling and peer contracts to verify wire-format
|
|
393
|
+
/// compatibility.
|
|
411
394
|
fn oft_version(_env: &soroban_sdk::Env) -> (u64, u64) {
|
|
412
395
|
(1, 1)
|
|
413
396
|
}
|
|
414
397
|
|
|
415
|
-
///
|
|
398
|
+
/// Returns the **shared decimals** — the common decimal precision used in cross-chain
|
|
399
|
+
/// messages.
|
|
400
|
+
///
|
|
401
|
+
/// Token amounts are normalized to this precision before encoding into LayerZero
|
|
402
|
+
/// messages, ensuring consistent values regardless of each chain's native token
|
|
403
|
+
/// decimals. For example, a token with 18 local decimals and 6 shared decimals has a
|
|
404
|
+
/// conversion rate of 10^12.
|
|
416
405
|
fn shared_decimals(env: &soroban_sdk::Env) -> u32 {
|
|
417
406
|
Self::__shared_decimals(env)
|
|
418
407
|
}
|
|
419
408
|
|
|
420
|
-
///
|
|
409
|
+
/// Returns the **decimal conversion rate** (`10 ^ (local_decimals - shared_decimals)`).
|
|
410
|
+
///
|
|
411
|
+
/// This multiplier converts between local-decimal amounts (used on-chain) and
|
|
412
|
+
/// shared-decimal amounts (used in cross-chain messages). Any sub-conversion-rate
|
|
413
|
+
/// remainder ("dust") is stripped before sending to avoid rounding discrepancies
|
|
414
|
+
/// across chains.
|
|
421
415
|
fn decimal_conversion_rate(env: &soroban_sdk::Env) -> i128 {
|
|
422
416
|
Self::__decimal_conversion_rate(env)
|
|
423
417
|
}
|
|
424
418
|
|
|
425
|
-
///
|
|
419
|
+
/// Indicates whether the caller must approve a token allowance before calling [`send`](OFTCore::send).
|
|
426
420
|
///
|
|
427
|
-
///
|
|
421
|
+
/// - **`false`** (default) — the OFT contract itself controls the token (mint-burn model),
|
|
422
|
+
/// so no prior approval is needed.
|
|
423
|
+
/// - **`true`** — the OFT locks externally owned tokens (adapter model), requiring the
|
|
424
|
+
/// sender to call `token.approve(oft_address, amount)` beforehand.
|
|
428
425
|
///
|
|
429
|
-
///
|
|
430
|
-
///
|
|
431
|
-
/// - `false` if no separate approval is needed
|
|
426
|
+
/// Wallet and frontend integrators should check this to determine whether an approval
|
|
427
|
+
/// transaction must precede the send.
|
|
432
428
|
fn approval_required(_env: &soroban_sdk::Env) -> bool {
|
|
433
429
|
false
|
|
434
430
|
}
|
|
435
431
|
|
|
436
|
-
/// Returns the message inspector address if
|
|
432
|
+
/// Returns the current message inspector contract address, or `None` if unset.
|
|
433
|
+
///
|
|
434
|
+
/// When set, the inspector's `inspect` method is invoked during both
|
|
435
|
+
/// [`quote_send`](OFTCore::quote_send) and [`send`](OFTCore::send) to validate the
|
|
436
|
+
/// outgoing message payload and options before they reach the LayerZero endpoint.
|
|
437
437
|
fn msg_inspector(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
|
|
438
438
|
Self::__msg_inspector(env)
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
-
/// Sets or removes the message inspector
|
|
441
|
+
/// Sets or removes the message inspector contract.
|
|
442
|
+
///
|
|
443
|
+
/// The message inspector is an **optional** validation hook. When configured, every
|
|
444
|
+
/// outbound message (from both `send` and `quote_send`) is passed to the inspector
|
|
445
|
+
/// contract's `inspect(contract, message, options)` method. The inspector should
|
|
446
|
+
/// **panic** to reject invalid messages, acting as an on-chain policy gate.
|
|
447
|
+
///
|
|
448
|
+
/// Pass `None` to remove the inspector and disable outbound validation.
|
|
442
449
|
///
|
|
443
|
-
///
|
|
444
|
-
///
|
|
445
|
-
/// method will be called during `send` and `quote_send` operations.
|
|
450
|
+
/// # Authorization
|
|
451
|
+
/// Requires owner authentication (`#[only_auth]`).
|
|
446
452
|
///
|
|
447
453
|
/// # Arguments
|
|
448
|
-
/// * `inspector` -
|
|
454
|
+
/// * `inspector` - Address of the inspector contract, or `None` to remove it
|
|
449
455
|
#[only_auth]
|
|
450
456
|
fn set_msg_inspector(env: &soroban_sdk::Env, inspector: &Option<soroban_sdk::Address>) {
|
|
451
457
|
Self::__set_msg_inspector(env, inspector);
|
|
452
458
|
}
|
|
453
459
|
|
|
454
|
-
///
|
|
460
|
+
/// Previews an OFT transfer **without executing** it.
|
|
455
461
|
///
|
|
456
|
-
///
|
|
457
|
-
///
|
|
462
|
+
/// Use this to display transfer details to the user before they commit. Returns:
|
|
463
|
+
///
|
|
464
|
+
/// - **`OFTLimit`** — the minimum and maximum transferable amounts in local decimals.
|
|
465
|
+
/// - **`Vec<OFTFeeDetail>`** — itemized fees (empty by default; populated when custom
|
|
466
|
+
/// fee logic is implemented via [`OFTInternal::__quote_oft`]).
|
|
467
|
+
/// - **`OFTReceipt`** — estimated `amount_sent_ld` and `amount_received_ld` after
|
|
468
|
+
/// dust removal and any fees.
|
|
469
|
+
///
|
|
470
|
+
/// # Arguments
|
|
471
|
+
/// * `from` - The address that would initiate the transfer
|
|
472
|
+
/// * `send_param` - The proposed transfer parameters (destination, amount, options, etc.)
|
|
458
473
|
fn quote_oft(
|
|
459
474
|
env: &soroban_sdk::Env,
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
475
|
+
from: &soroban_sdk::Address,
|
|
476
|
+
send_param: &oft_core::SendParam,
|
|
477
|
+
) -> (oft_core::OFTLimit, soroban_sdk::Vec<oft_core::OFTFeeDetail>, oft_core::OFTReceipt) {
|
|
478
|
+
Self::__quote_oft(env, from, send_param)
|
|
463
479
|
}
|
|
464
480
|
|
|
465
|
-
/// Quotes
|
|
481
|
+
/// Quotes the **LayerZero messaging fee** required for a cross-chain send.
|
|
482
|
+
///
|
|
483
|
+
/// Builds the outgoing message and options from `send_param`, then queries the
|
|
484
|
+
/// LayerZero endpoint for the corresponding fee. If a message inspector is set, it
|
|
485
|
+
/// will also validate the message at this stage.
|
|
486
|
+
///
|
|
487
|
+
/// # Arguments
|
|
488
|
+
/// * `from` - The address that would initiate the transfer
|
|
489
|
+
/// * `send_param` - The proposed transfer parameters
|
|
490
|
+
/// * `pay_in_zro` - `true` to pay the messaging fee in the ZRO token; `false` to pay
|
|
491
|
+
/// in the chain's native token
|
|
492
|
+
///
|
|
493
|
+
/// # Returns
|
|
494
|
+
/// A [`MessagingFee`](endpoint_v2::MessagingFee) containing the `native_fee` and
|
|
495
|
+
/// `zro_fee` required by the endpoint. Pass this value (or a superset) to
|
|
496
|
+
/// [`send`](OFTCore::send).
|
|
466
497
|
fn quote_send(
|
|
467
498
|
env: &soroban_sdk::Env,
|
|
468
499
|
from: &soroban_sdk::Address,
|
|
469
|
-
send_param: &oft_core::
|
|
500
|
+
send_param: &oft_core::SendParam,
|
|
470
501
|
pay_in_zro: bool,
|
|
471
502
|
) -> endpoint_v2::MessagingFee {
|
|
472
503
|
Self::__quote_send(env, from, send_param, pay_in_zro)
|
|
473
504
|
}
|
|
474
505
|
|
|
475
|
-
///
|
|
506
|
+
/// Executes a cross-chain token transfer via the LayerZero endpoint.
|
|
507
|
+
///
|
|
508
|
+
/// Builds the OFT message and options, then sends the message through the LayerZero endpoint.
|
|
476
509
|
///
|
|
477
|
-
///
|
|
510
|
+
/// # Arguments
|
|
511
|
+
/// * `from` - The token sender (must authorize the call)
|
|
512
|
+
/// * `send_param` - Transfer parameters including destination chain (`dst_eid`),
|
|
513
|
+
/// recipient (`to`), amount, slippage floor (`min_amount_ld`), extra options, and
|
|
514
|
+
/// an optional compose message
|
|
515
|
+
/// * `fee` - The messaging fee to pay (obtain from [`quote_send`](OFTCore::quote_send))
|
|
516
|
+
/// * `refund_address` - Address to receive any excess fee refund
|
|
478
517
|
///
|
|
479
518
|
/// # Returns
|
|
480
|
-
/// (MessagingReceipt,
|
|
519
|
+
/// * [`MessagingReceipt`](endpoint_v2::MessagingReceipt) — the LayerZero message GUID,
|
|
520
|
+
/// nonce, and fee actually consumed
|
|
521
|
+
/// * [`OFTReceipt`](crate::types::OFTReceipt) — `amount_sent_ld` (debited) and
|
|
522
|
+
/// `amount_received_ld` (credited on destination after dust removal / fees)
|
|
481
523
|
fn send(
|
|
482
524
|
env: &soroban_sdk::Env,
|
|
483
525
|
from: &soroban_sdk::Address,
|
|
484
|
-
send_param: &oft_core::
|
|
526
|
+
send_param: &oft_core::SendParam,
|
|
485
527
|
fee: &endpoint_v2::MessagingFee,
|
|
486
528
|
refund_address: &soroban_sdk::Address,
|
|
487
|
-
) -> (endpoint_v2::MessagingReceipt, oft_core::
|
|
529
|
+
) -> (endpoint_v2::MessagingReceipt, oft_core::OFTReceipt) {
|
|
488
530
|
Self::__send(env, from, send_param, fee, refund_address)
|
|
489
531
|
}
|
|
490
532
|
}
|
|
@@ -532,3 +574,18 @@ macro_rules! impl_oft_lz_receive {
|
|
|
532
574
|
}
|
|
533
575
|
};
|
|
534
576
|
}
|
|
577
|
+
|
|
578
|
+
// ===========================================================================
|
|
579
|
+
// Helper Functions
|
|
580
|
+
// ===========================================================================
|
|
581
|
+
|
|
582
|
+
/// Asserts that the send amount and min_amount are nonnegative.
|
|
583
|
+
/// # Arguments
|
|
584
|
+
/// * `env` - The environment
|
|
585
|
+
/// * `send_param` - The send parameters to assert
|
|
586
|
+
///
|
|
587
|
+
/// # Panics
|
|
588
|
+
/// * `OFTError::InvalidAmount` - If the send amount or min_amount is negative
|
|
589
|
+
pub fn assert_nonnegative_amount(env: &Env, send_param: &SendParam) {
|
|
590
|
+
assert_with_error!(env, send_param.amount_ld >= 0 && send_param.min_amount_ld >= 0, OFTError::InvalidAmount);
|
|
591
|
+
}
|
|
@@ -3,11 +3,13 @@ use soroban_sdk::Address;
|
|
|
3
3
|
|
|
4
4
|
#[storage]
|
|
5
5
|
pub enum OFTStorage {
|
|
6
|
-
/// The difference between local and shared decimals (local_decimals - shared_decimals)
|
|
6
|
+
/// The difference between local and shared decimals (local_decimals - shared_decimals).
|
|
7
|
+
/// Immutable: set once during construction and never modified.
|
|
7
8
|
#[instance(u32)]
|
|
8
9
|
DecimalsDiff,
|
|
9
10
|
|
|
10
|
-
/// The address of the underlying token contract
|
|
11
|
+
/// The address of the underlying token contract.
|
|
12
|
+
/// Immutable: set once during construction and never modified.
|
|
11
13
|
#[instance(Address)]
|
|
12
14
|
Token,
|
|
13
15
|
|
|
@@ -17,7 +17,7 @@ fn test_decimal_conversion_rate() {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
#[test]
|
|
20
|
-
#[should_panic(expected = "Error(Contract, #
|
|
20
|
+
#[should_panic(expected = "Error(Contract, #3002)")] // InvalidLocalDecimals
|
|
21
21
|
fn test_invalid_local_decimals() {
|
|
22
22
|
let env = Env::default();
|
|
23
23
|
OFTTestSetupBuilder::new(&env).with_token_decimals(5).with_shared_decimals(6).build();
|
|
@@ -34,7 +34,7 @@ fn test_to_ld_overflow() {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
#[test]
|
|
37
|
-
#[should_panic(expected = "Error(Contract, #
|
|
37
|
+
#[should_panic(expected = "Error(Contract, #3004)")] // Overflow
|
|
38
38
|
fn test_to_sd_overflow() {
|
|
39
39
|
let env = Env::default();
|
|
40
40
|
|