@layerzerolabs/protocol-stellar-v2 0.2.8 → 0.2.10
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 +443 -302
- package/.turbo/turbo-lint.log +118 -96
- package/.turbo/turbo-test.log +853 -731
- package/Cargo.lock +120 -37
- package/Cargo.toml +8 -5
- package/contracts/common-macros/src/contract_impl.rs +44 -0
- package/contracts/common-macros/src/lib.rs +86 -40
- package/contracts/common-macros/src/ownable.rs +24 -32
- package/contracts/common-macros/src/storage.rs +95 -120
- package/contracts/common-macros/src/tests/contract_impl.rs +289 -0
- package/contracts/common-macros/src/tests/mod.rs +9 -0
- package/contracts/common-macros/src/tests/ownable.rs +151 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_impl__snapshot_generated_contract_impl_code.snap +85 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_generated_ownable_code.snap +30 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_only_owner_preserves_function_signature.snap +9 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__storage__snapshot_generated_storage_code.snap +1072 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +45 -0
- package/contracts/common-macros/src/tests/storage.rs +485 -0
- package/contracts/common-macros/src/tests/test_helpers.rs +93 -0
- package/contracts/common-macros/src/tests/ttl_configurable.rs +34 -0
- package/contracts/common-macros/src/ttl_configurable.rs +31 -14
- package/contracts/common-macros/src/utils.rs +27 -0
- package/contracts/endpoint-v2/ARCHITECTURE.md +4 -4
- package/contracts/endpoint-v2/src/endpoint_v2.rs +18 -15
- package/contracts/endpoint-v2/src/interfaces/message_lib.rs +2 -3
- package/contracts/endpoint-v2/src/interfaces/message_lib_manager.rs +5 -3
- package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +2 -2
- package/contracts/endpoint-v2/src/interfaces/messaging_composer.rs +2 -2
- package/contracts/endpoint-v2/src/interfaces/send_lib.rs +4 -4
- package/contracts/endpoint-v2/src/lib.rs +6 -5
- package/contracts/endpoint-v2/src/message_lib_manager.rs +14 -6
- package/contracts/endpoint-v2/src/messaging_channel.rs +6 -2
- package/contracts/endpoint-v2/src/messaging_composer.rs +6 -2
- package/contracts/endpoint-v2/src/storage.rs +10 -7
- package/contracts/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +16 -16
- package/contracts/endpoint-v2/src/tests/endpoint_v2/ttl_config.rs +46 -46
- package/contracts/endpoint-v2/src/tests/mock.rs +2 -2
- package/contracts/endpoint-v2/src/util.rs +8 -2
- package/contracts/message-libs/block-message-lib/Cargo.toml +1 -0
- package/contracts/message-libs/block-message-lib/src/lib.rs +5 -5
- package/contracts/message-libs/message-lib-common/src/errors.rs +8 -8
- package/contracts/message-libs/message-lib-common/src/interfaces/dvn.rs +0 -1
- package/contracts/message-libs/message-lib-common/src/interfaces/mod.rs +3 -3
- package/contracts/message-libs/message-lib-common/src/lib.rs +0 -2
- package/contracts/message-libs/message-lib-common/src/packet_codec_v1.rs +4 -6
- package/contracts/message-libs/message-lib-common/src/tests/packet_codec_v1.rs +2 -2
- package/contracts/message-libs/message-lib-common/src/tests/worker_options.rs +11 -11
- package/contracts/message-libs/message-lib-common/src/worker_options.rs +10 -16
- package/contracts/message-libs/simple-message-lib/src/errors.rs +0 -4
- package/contracts/message-libs/simple-message-lib/src/simple_message_lib.rs +49 -34
- package/contracts/message-libs/simple-message-lib/src/storage.rs +3 -7
- package/contracts/message-libs/simple-message-lib/src/test.rs +3 -3
- package/contracts/message-libs/treasury/src/storage.rs +1 -2
- package/contracts/message-libs/treasury/src/tests/setup.rs +3 -2
- package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +0 -13
- package/contracts/message-libs/treasury/src/treasury.rs +18 -21
- package/contracts/message-libs/uln-302/Cargo.toml +1 -0
- package/contracts/message-libs/uln-302/src/interfaces/mod.rs +4 -4
- package/contracts/message-libs/uln-302/src/interfaces/{receive.rs → receive_uln.rs} +3 -3
- package/contracts/message-libs/uln-302/src/interfaces/{send.rs → send_uln.rs} +8 -80
- package/contracts/message-libs/uln-302/src/lib.rs +5 -4
- package/contracts/message-libs/uln-302/src/{receive.rs → receive_uln.rs} +20 -12
- package/contracts/message-libs/uln-302/src/{send.rs → send_uln.rs} +19 -13
- package/contracts/message-libs/uln-302/src/storage.rs +1 -2
- package/contracts/message-libs/uln-302/src/tests/config/uln_config.rs +3 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +30 -30
- package/contracts/message-libs/uln-302/src/tests/setup.rs +12 -11
- package/contracts/message-libs/uln-302/src/tests/uln302/set_config.rs +1 -1
- package/contracts/message-libs/uln-302/src/{config_validation.rs → types.rs} +79 -11
- package/contracts/message-libs/uln-302/src/uln302.rs +15 -10
- package/contracts/oapp-macros/Cargo.toml +2 -8
- package/contracts/oapp-macros/src/lib.rs +57 -311
- package/contracts/oapp-macros/src/oapp_core.rs +23 -32
- package/contracts/oapp-macros/src/oapp_full.rs +8 -2
- package/contracts/oapp-macros/src/oapp_options_type3.rs +21 -36
- package/contracts/oapp-macros/src/oapp_receiver.rs +38 -57
- package/contracts/oapp-macros/src/oapp_sender.rs +12 -14
- package/contracts/oapp-macros/src/util.rs +14 -10
- package/contracts/oapps/counter/Cargo.toml +2 -1
- package/contracts/oapps/counter/integration_tests/utils.rs +4 -4
- package/contracts/oapps/counter/src/codec.rs +8 -9
- package/contracts/oapps/counter/src/counter.rs +156 -147
- package/contracts/oapps/counter/src/storage.rs +1 -2
- package/contracts/oapps/counter/src/tests/test_codec.rs +5 -5
- package/contracts/oapps/counter/src/tests/test_counter.rs +11 -13
- package/contracts/oapps/oapp/Cargo.toml +1 -0
- package/contracts/oapps/oapp/src/errors.rs +1 -1
- package/contracts/oapps/oapp/src/lib.rs +3 -0
- package/contracts/oapps/oapp/src/macro_tests/mod.rs +1 -0
- package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +312 -0
- package/contracts/oapps/oapp/src/oapp_core.rs +52 -53
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +18 -28
- package/contracts/oapps/oapp/src/oapp_receiver.rs +82 -31
- package/contracts/oapps/oapp/src/oapp_sender.rs +55 -13
- package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +16 -3
- package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +33 -8
- package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +6 -9
- package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +28 -15
- package/contracts/oapps/oft/Cargo.toml +27 -0
- package/contracts/oapps/oft/integration-tests/mod.rs +3 -0
- package/contracts/oapps/oft/integration-tests/setup.rs +320 -0
- package/contracts/oapps/oft/integration-tests/test_with_sml.rs +155 -0
- package/contracts/oapps/oft/integration-tests/utils.rs +201 -0
- package/contracts/oapps/oft/src/codec/mod.rs +2 -0
- package/contracts/oapps/oft/src/codec/oft_compose_msg_codec.rs +55 -0
- package/contracts/oapps/oft/src/codec/oft_msg_codec.rs +62 -0
- package/contracts/oapps/oft/src/constants.rs +5 -0
- package/contracts/oapps/oft/src/errors.rs +8 -0
- package/contracts/oapps/oft/src/events.rs +19 -0
- package/contracts/oapps/oft/src/interfaces/mint_burn_token.rs +23 -0
- package/contracts/oapps/oft/src/interfaces/mod.rs +3 -0
- package/contracts/oapps/oft/src/lib.rs +22 -0
- package/contracts/oapps/oft/src/macro_tests/mod.rs +2 -0
- package/contracts/oapps/oft/src/macro_tests/test_all_default.rs +41 -0
- package/contracts/oapps/oft/src/macro_tests/test_override.rs +83 -0
- package/contracts/oapps/oft/src/oft.rs +320 -0
- package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +50 -0
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +50 -0
- package/contracts/oapps/oft/src/oft_types/mod.rs +10 -0
- package/contracts/oapps/oft/src/storage.rs +11 -0
- package/contracts/oapps/oft/src/tests/mod.rs +13 -0
- package/contracts/oapps/oft/src/tests/test_decimals.rs +89 -0
- package/contracts/oapps/oft/src/tests/test_lz_receive.rs +282 -0
- package/contracts/oapps/oft/src/tests/test_oft_compose_msg_codec.rs +68 -0
- package/contracts/oapps/oft/src/tests/test_oft_msg_codec.rs +136 -0
- package/contracts/oapps/oft/src/tests/test_oft_version.rs +13 -0
- package/contracts/oapps/oft/src/tests/test_quote_oft.rs +159 -0
- package/contracts/oapps/oft/src/tests/test_quote_send.rs +195 -0
- package/contracts/oapps/oft/src/tests/test_resolve_address.rs +37 -0
- package/contracts/oapps/oft/src/tests/test_send.rs +915 -0
- package/contracts/oapps/oft/src/tests/test_token.rs +47 -0
- package/contracts/oapps/oft/src/tests/test_utils.rs +789 -0
- package/contracts/oapps/oft/src/types.rs +38 -0
- package/contracts/oapps/oft/src/utils.rs +67 -0
- package/contracts/oapps/oft-mint-burn/Cargo.toml +26 -0
- package/contracts/oapps/oft-mint-burn/src/lib.rs +3 -0
- package/contracts/oapps/oft-mint-burn/src/oft.rs +28 -0
- package/contracts/oapps/oft-mint-burn/src/tests/mod.rs +1 -0
- package/contracts/utils/src/buffer_reader.rs +8 -9
- package/contracts/utils/src/buffer_writer.rs +11 -5
- package/contracts/utils/src/errors.rs +5 -5
- package/contracts/utils/src/ownable.rs +14 -6
- package/contracts/utils/src/testing_utils.rs +11 -1
- package/contracts/utils/src/tests/buffer_reader.rs +491 -730
- package/contracts/utils/src/tests/buffer_writer.rs +336 -148
- package/contracts/utils/src/tests/bytes_ext.rs +125 -40
- package/contracts/utils/src/tests/mod.rs +3 -0
- package/contracts/utils/src/tests/ownable.rs +379 -27
- package/contracts/utils/src/tests/test_helper.rs +47 -0
- package/contracts/utils/src/tests/testing_utils.rs +555 -0
- package/contracts/utils/src/tests/ttl.rs +421 -0
- package/contracts/utils/src/ttl.rs +29 -89
- package/contracts/workers/dvn/Cargo.toml +31 -0
- package/contracts/workers/dvn/src/auth.rs +66 -0
- package/contracts/workers/dvn/src/dvn.rs +143 -0
- package/contracts/workers/dvn/src/errors.rs +21 -0
- package/contracts/workers/dvn/src/events.rs +19 -0
- package/contracts/workers/dvn/src/interfaces/dvn.rs +12 -0
- package/contracts/workers/dvn/src/interfaces/mod.rs +5 -0
- package/contracts/workers/dvn/src/interfaces/multisig.rs +15 -0
- package/contracts/workers/dvn/src/lib.rs +24 -0
- package/contracts/workers/dvn/src/multisig.rs +127 -0
- package/contracts/workers/dvn/src/storage.rs +35 -0
- package/contracts/workers/dvn/src/tests/auth.rs +237 -0
- package/contracts/workers/dvn/src/tests/dvn.rs +349 -0
- package/contracts/workers/dvn/src/tests/key_pair.rs +66 -0
- package/contracts/workers/dvn/src/tests/mod.rs +5 -0
- package/contracts/workers/dvn/src/tests/multisig/mod.rs +3 -0
- package/contracts/workers/dvn/src/tests/multisig/set_signer.rs +133 -0
- package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +108 -0
- package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +109 -0
- package/contracts/workers/dvn/src/tests/setup.rs +109 -0
- package/contracts/workers/dvn/src/types.rs +26 -0
- package/contracts/workers/dvn-fee-lib/Cargo.toml +24 -0
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +113 -0
- package/contracts/workers/dvn-fee-lib/src/errors.rs +8 -0
- package/contracts/workers/dvn-fee-lib/src/lib.rs +17 -0
- package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +282 -0
- package/contracts/workers/dvn-fee-lib/src/tests/mod.rs +1 -0
- package/contracts/workers/executor/Cargo.toml +10 -7
- package/contracts/workers/executor/src/errors.rs +8 -0
- package/contracts/workers/executor/src/events.rs +4 -7
- package/contracts/workers/executor/src/interfaces/executor.rs +72 -22
- package/contracts/workers/executor/src/interfaces/mod.rs +0 -2
- package/contracts/workers/executor/src/lib.rs +16 -7
- package/contracts/workers/executor/src/lz_executor.rs +308 -0
- package/contracts/workers/executor/src/storage.rs +24 -16
- package/contracts/workers/executor-fee-lib/Cargo.toml +22 -0
- package/contracts/workers/executor-fee-lib/src/errors.rs +15 -0
- package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +215 -0
- package/contracts/workers/executor-fee-lib/src/executor_option.rs +203 -0
- package/contracts/workers/executor-fee-lib/src/lib.rs +7 -0
- package/contracts/workers/executor-helper/Cargo.toml +29 -0
- package/contracts/workers/executor-helper/src/executor_helper.rs +161 -0
- package/contracts/workers/executor-helper/src/lib.rs +11 -0
- package/contracts/workers/{worker-common → worker}/Cargo.toml +1 -4
- package/contracts/workers/worker/src/errors.rs +24 -0
- package/contracts/workers/worker/src/events.rs +62 -0
- package/contracts/workers/worker/src/interfaces/dvn_fee_lib.rs +75 -0
- package/contracts/workers/worker/src/interfaces/executor_fee_lib.rs +84 -0
- package/contracts/workers/{worker-common → worker}/src/interfaces/mod.rs +2 -2
- package/contracts/workers/worker/src/interfaces/price_feed.rs +85 -0
- package/contracts/workers/worker/src/lib.rs +14 -0
- package/contracts/workers/worker/src/storage.rs +63 -0
- package/contracts/workers/worker/src/worker.rs +459 -0
- package/package.json +3 -3
- package/sdk/dist/generated/bml.d.ts +88 -17
- package/sdk/dist/generated/bml.js +62 -16
- package/sdk/dist/generated/counter.d.ts +281 -102
- package/sdk/dist/generated/counter.js +93 -41
- package/sdk/dist/generated/endpoint.d.ts +128 -105
- package/sdk/dist/generated/endpoint.js +47 -45
- package/sdk/dist/generated/sml.d.ts +212 -69
- package/sdk/dist/generated/sml.js +103 -53
- package/sdk/dist/generated/uln302.d.ts +270 -173
- package/sdk/dist/generated/uln302.js +112 -64
- package/sdk/package.json +11 -11
- package/sdk/test/index.test.ts +147 -42
- package/sdk/test/suites/constants.ts +7 -3
- package/sdk/test/suites/deploy.ts +65 -42
- package/sdk/test/suites/localnet.ts +2 -2
- package/sdk/test/suites/scan.ts +28 -25
- package/sdk/test/utils.ts +199 -0
- package/sdk/tsconfig.json +93 -95
- package/tools/ts-bindings-gen/src/main.rs +2 -0
- package/contracts/common-macros/src/snapshots/common_macros__tests__tests__snapshot_generated_storage_code.snap +0 -310
- package/contracts/common-macros/src/tests.rs +0 -287
- package/contracts/oapp-macros/tests/test_macros.rs +0 -522
- package/contracts/workers/executor/src/executor.rs +0 -347
- package/contracts/workers/executor/src/interfaces/types.rs +0 -51
- package/contracts/workers/worker-common/src/constants.rs +0 -17
- package/contracts/workers/worker-common/src/errors.rs +0 -6
- package/contracts/workers/worker-common/src/events.rs +0 -34
- package/contracts/workers/worker-common/src/interfaces/executor_fee_lib.rs +0 -35
- package/contracts/workers/worker-common/src/interfaces/price_feed.rs +0 -40
- package/contracts/workers/worker-common/src/interfaces/worker.rs +0 -60
- package/contracts/workers/worker-common/src/lib.rs +0 -19
- package/contracts/workers/worker-common/src/storage.rs +0 -32
- package/contracts/workers/worker-common/src/worker_common.rs +0 -166
|
@@ -0,0 +1,789 @@
|
|
|
1
|
+
//! Shared test utilities for OFT unit tests.
|
|
2
|
+
//!
|
|
3
|
+
//! This module provides common test contracts and helpers used across multiple test files.
|
|
4
|
+
|
|
5
|
+
extern crate self as oft;
|
|
6
|
+
|
|
7
|
+
use crate::codec::oft_msg_codec::OFTMessage;
|
|
8
|
+
use crate::oft::{oft_initialize, OFTClient, OFTInner, OFT};
|
|
9
|
+
use crate::types::{OFTReceipt, SendParam};
|
|
10
|
+
use endpoint_v2::{LayerZeroReceiverClient, MessagingFee, MessagingParams, MessagingReceipt, Origin};
|
|
11
|
+
use oapp::oapp_core::OAppCoreClient;
|
|
12
|
+
use oapp::oapp_receiver::OAppReceiver;
|
|
13
|
+
use oapp_macros::oapp_manual_impl;
|
|
14
|
+
use soroban_sdk::{address_payload::AddressPayload, log, String};
|
|
15
|
+
use soroban_sdk::{
|
|
16
|
+
bytes, contract, contractimpl, symbol_short,
|
|
17
|
+
testutils::{Address as _, MockAuth, MockAuthInvoke},
|
|
18
|
+
token::{StellarAssetClient, TokenClient},
|
|
19
|
+
Address, Bytes, BytesN, Env, IntoVal, Symbol,
|
|
20
|
+
};
|
|
21
|
+
use stellar_macros::default_impl;
|
|
22
|
+
use stellar_tokens::fungible::{Base, FungibleToken};
|
|
23
|
+
|
|
24
|
+
// ==================== Constants ====================
|
|
25
|
+
|
|
26
|
+
/// Default shared decimals used for cross-chain normalization in tests
|
|
27
|
+
pub const DEFAULT_SHARED_DECIMALS: u32 = 6;
|
|
28
|
+
|
|
29
|
+
// ==================== Helper Functions ====================
|
|
30
|
+
|
|
31
|
+
/// Create a SendParam for testing with default options.
|
|
32
|
+
pub fn create_send_param(env: &Env, dst_eid: u32, amount_ld: i128, min_amount_ld: i128) -> SendParam {
|
|
33
|
+
SendParam {
|
|
34
|
+
dst_eid,
|
|
35
|
+
to: BytesN::from_array(env, &[1u8; 32]),
|
|
36
|
+
amount_ld,
|
|
37
|
+
min_amount_ld,
|
|
38
|
+
extra_options: bytes!(env),
|
|
39
|
+
compose_msg: bytes!(env),
|
|
40
|
+
oft_cmd: bytes!(env),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Creates a valid recipient address by deploying a dummy contract.
|
|
45
|
+
/// Use this in tests when the address needs to pass the `.exists()` check.
|
|
46
|
+
pub fn create_recipient_address(env: &Env) -> Address {
|
|
47
|
+
env.register(DummyRecipient, ())
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Creates a G-address (account address) from a 32-byte Ed25519 public key.
|
|
51
|
+
/// This is useful for testing with account addresses instead of contract addresses.
|
|
52
|
+
pub fn create_g_address(env: &Env, public_key: &BytesN<32>) -> Address {
|
|
53
|
+
Address::from_payload(env, AddressPayload::AccountIdPublicKeyEd25519(public_key.clone()))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// Generates a unique G-address (account address) for testing.
|
|
57
|
+
/// Each call generates a different address by using a counter-based approach.
|
|
58
|
+
pub fn generate_g_address(env: &Env) -> Address {
|
|
59
|
+
// Use Address::generate which creates a unique address each time
|
|
60
|
+
// Then convert it to ensure it's a G-address (account address)
|
|
61
|
+
let addr = Address::generate(env);
|
|
62
|
+
// Extract the payload - if it's already a G-address, use it; otherwise convert
|
|
63
|
+
match addr.to_payload() {
|
|
64
|
+
Some(AddressPayload::AccountIdPublicKeyEd25519(_pk)) => {
|
|
65
|
+
// Already a G-address, return as-is
|
|
66
|
+
addr
|
|
67
|
+
}
|
|
68
|
+
Some(AddressPayload::ContractIdHash(hash)) => {
|
|
69
|
+
// It's a contract address, convert hash to G-address
|
|
70
|
+
// Use the hash bytes as the Ed25519 public key
|
|
71
|
+
create_g_address(env, &hash)
|
|
72
|
+
}
|
|
73
|
+
None => {
|
|
74
|
+
// Fallback: create from hash bytes
|
|
75
|
+
let hash = BytesN::from_array(env, &[0u8; 32]);
|
|
76
|
+
create_g_address(env, &hash)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
pub fn encode_oft_message(env: &Env, send_to: &BytesN<32>, amount_sd: u64) -> Bytes {
|
|
82
|
+
let msg = OFTMessage { send_to: send_to.clone(), amount_sd, compose_from: None, compose_msg: None };
|
|
83
|
+
msg.encode(env).0
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
pub fn encode_oft_message_with_compose(
|
|
87
|
+
env: &Env,
|
|
88
|
+
send_to: &BytesN<32>,
|
|
89
|
+
amount_sd: u64,
|
|
90
|
+
compose_from: &BytesN<32>,
|
|
91
|
+
compose_msg: &Bytes,
|
|
92
|
+
) -> Bytes {
|
|
93
|
+
let msg = OFTMessage {
|
|
94
|
+
send_to: send_to.clone(),
|
|
95
|
+
amount_sd,
|
|
96
|
+
compose_from: Some(compose_from.clone()),
|
|
97
|
+
compose_msg: Some(compose_msg.clone()),
|
|
98
|
+
};
|
|
99
|
+
msg.encode(env).0
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
pub fn create_origin(src_eid: u32, sender: &BytesN<32>, nonce: u64) -> Origin {
|
|
103
|
+
Origin { src_eid, sender: sender.clone(), nonce }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ==================== Test OFT Contract ====================
|
|
107
|
+
|
|
108
|
+
#[oapp_macros::oapp]
|
|
109
|
+
pub struct TestMintBurnOFT;
|
|
110
|
+
|
|
111
|
+
#[contractimpl]
|
|
112
|
+
impl TestMintBurnOFT {
|
|
113
|
+
pub fn __constructor(env: &Env, token: &Address, owner: &Address, endpoint: &Address, delegate: &Option<Address>) {
|
|
114
|
+
oft_initialize::<Self>(env, owner, token, endpoint, delegate)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#[contractimpl(contracttrait)]
|
|
119
|
+
impl OFT for TestMintBurnOFT {}
|
|
120
|
+
|
|
121
|
+
impl OFTInner for TestMintBurnOFT {
|
|
122
|
+
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
123
|
+
crate::oft_types::mint_burn::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fn __credit(env: &Env, to: &Address, amount_ld: i128, src_eid: u32) -> i128 {
|
|
127
|
+
crate::oft_types::mint_burn::credit::<Self>(env, to, amount_ld, src_eid)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#[oapp_macros::oapp]
|
|
132
|
+
#[oapp_manual_impl(receiver)]
|
|
133
|
+
pub struct TestLockUnlockOFT;
|
|
134
|
+
|
|
135
|
+
#[contractimpl]
|
|
136
|
+
impl TestLockUnlockOFT {
|
|
137
|
+
pub fn __constructor(env: &Env, token: &Address, owner: &Address, endpoint: &Address, delegate: &Option<Address>) {
|
|
138
|
+
oft_initialize::<Self>(env, owner, token, endpoint, delegate)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#[contractimpl(contracttrait)]
|
|
143
|
+
impl OFT for TestLockUnlockOFT {}
|
|
144
|
+
|
|
145
|
+
#[contractimpl(contracttrait)]
|
|
146
|
+
impl OAppReceiver for TestLockUnlockOFT {
|
|
147
|
+
fn lz_receive(
|
|
148
|
+
env: &Env,
|
|
149
|
+
executor: &Address,
|
|
150
|
+
origin: &Origin,
|
|
151
|
+
guid: &BytesN<32>,
|
|
152
|
+
message: &Bytes,
|
|
153
|
+
extra_data: &Bytes,
|
|
154
|
+
value: i128,
|
|
155
|
+
) {
|
|
156
|
+
oapp::oapp_receiver::verify_and_clear_payload::<Self>(env, executor, origin, guid, message, value);
|
|
157
|
+
Self::__lz_receive(env, executor, origin, guid, message, extra_data, value);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
impl OFTInner for TestLockUnlockOFT {
|
|
162
|
+
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
163
|
+
crate::oft_types::lock_unlock::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
fn __credit(env: &Env, to: &Address, amount_ld: i128, src_eid: u32) -> i128 {
|
|
167
|
+
crate::oft_types::lock_unlock::credit::<Self>(env, to, amount_ld, src_eid)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ==================== Dummy Contracts ====================
|
|
172
|
+
|
|
173
|
+
/// Dummy recipient contract for testing - used to create valid contract addresses
|
|
174
|
+
#[contract]
|
|
175
|
+
pub struct DummyRecipient;
|
|
176
|
+
|
|
177
|
+
#[contractimpl]
|
|
178
|
+
impl DummyRecipient {
|
|
179
|
+
pub fn __constructor(_env: &Env) {}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
#[contract]
|
|
183
|
+
pub struct DummyToken;
|
|
184
|
+
|
|
185
|
+
#[contractimpl]
|
|
186
|
+
impl DummyToken {
|
|
187
|
+
fn admin(env: &Env) -> Address {
|
|
188
|
+
env.storage().instance().get(&symbol_short!("admin")).unwrap()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
pub fn __constructor(env: &Env, owner: Address, decimals: u32) {
|
|
192
|
+
Base::set_metadata(env, decimals, String::from_str(env, "DummyToken"), String::from_str(env, "DUMMY"));
|
|
193
|
+
env.storage().instance().set(&symbol_short!("admin"), &owner);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// keep the same behavior as SAC that requires admin's authorization
|
|
197
|
+
pub fn set_admin(env: &Env, admin: &Address) {
|
|
198
|
+
Self::admin(env).require_auth();
|
|
199
|
+
env.storage().instance().set(&symbol_short!("admin"), &admin);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
pub fn mint(env: &Env, to: &Address, amount: i128) {
|
|
203
|
+
Self::admin(env).require_auth();
|
|
204
|
+
Base::mint(env, &to, amount);
|
|
205
|
+
log!(&env, "minted {} to {}", amount, to);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// keep the same behavior as SAC that requires from's authorization
|
|
209
|
+
pub fn burn(env: &Env, from: &Address, amount: i128) {
|
|
210
|
+
Base::burn(env, &from, amount);
|
|
211
|
+
log!(&env, "burned {} from {}", amount, from);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
#[default_impl]
|
|
216
|
+
#[contractimpl]
|
|
217
|
+
impl FungibleToken for DummyToken {
|
|
218
|
+
type ContractType = Base;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ==================== Mock Endpoint ====================
|
|
222
|
+
|
|
223
|
+
/// A comprehensive mock endpoint contract for testing OFT functionality.
|
|
224
|
+
/// Supports: quote, set_delegate, clear, send_compose, and compose verification.
|
|
225
|
+
#[contract]
|
|
226
|
+
pub struct MockEndpointWithCompose;
|
|
227
|
+
|
|
228
|
+
#[contractimpl]
|
|
229
|
+
impl MockEndpointWithCompose {
|
|
230
|
+
pub fn __constructor(env: Env, native_fee: i128, zro_fee: i128, native_token: Address, zro_token: Address) {
|
|
231
|
+
env.storage().instance().set(&symbol_short!("ntv_fee"), &native_fee);
|
|
232
|
+
env.storage().instance().set(&symbol_short!("zro_fee"), &zro_fee);
|
|
233
|
+
env.storage().instance().set(&symbol_short!("ntk"), &native_token);
|
|
234
|
+
env.storage().instance().set(&symbol_short!("zro"), &zro_token);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/// Returns the native token address (required by OAppSender)
|
|
238
|
+
pub fn native_token(env: Env) -> Address {
|
|
239
|
+
env.storage().instance().get(&symbol_short!("ntk")).unwrap()
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/// Returns the ZRO token address (required by OAppSender)
|
|
243
|
+
pub fn zro(env: Env) -> Option<Address> {
|
|
244
|
+
env.storage().instance().get(&symbol_short!("zro"))
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/// Required by OApp initialization to set delegate
|
|
248
|
+
pub fn set_delegate(_env: Env, _oapp: Address, _delegate: Option<Address>) {
|
|
249
|
+
// No-op for testing
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/// Required by OAppReceiver.lz_receive to clear the payload
|
|
253
|
+
pub fn clear(_env: Env, _oapp: Address, _origin: Origin, _receiver: Address, _guid: BytesN<32>, _message: Bytes) {
|
|
254
|
+
// No-op for testing
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/// Required by quote_send to get messaging fees
|
|
258
|
+
pub fn quote(env: Env, _sender: Address, params: MessagingParams) -> MessagingFee {
|
|
259
|
+
let native_fee: i128 = env.storage().instance().get(&symbol_short!("ntv_fee")).unwrap_or(1000);
|
|
260
|
+
let zro_fee: i128 =
|
|
261
|
+
if params.pay_in_zro { env.storage().instance().get(&symbol_short!("zro_fee")).unwrap_or(500) } else { 0 };
|
|
262
|
+
MessagingFee { native_fee, zro_fee }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/// Required by send to send cross-chain messages
|
|
266
|
+
pub fn send(env: Env, _sender: Address, params: MessagingParams, _refund_address: Address) -> MessagingReceipt {
|
|
267
|
+
// Increment nonce for each send
|
|
268
|
+
let nonce: u64 = env.storage().instance().get(&symbol_short!("nonce")).unwrap_or(0) + 1;
|
|
269
|
+
env.storage().instance().set(&symbol_short!("nonce"), &nonce);
|
|
270
|
+
|
|
271
|
+
// Store send details for verification
|
|
272
|
+
env.storage().instance().set(&symbol_short!("sent"), &true);
|
|
273
|
+
env.storage().instance().set(&Symbol::new(&env, "last_dst_eid"), ¶ms.dst_eid);
|
|
274
|
+
env.storage().instance().set(&Symbol::new(&env, "last_msg"), ¶ms.message);
|
|
275
|
+
|
|
276
|
+
let native_fee: i128 = env.storage().instance().get(&symbol_short!("ntv_fee")).unwrap_or(1000);
|
|
277
|
+
let zro_fee: i128 =
|
|
278
|
+
if params.pay_in_zro { env.storage().instance().get(&symbol_short!("zro_fee")).unwrap_or(500) } else { 0 };
|
|
279
|
+
|
|
280
|
+
MessagingReceipt {
|
|
281
|
+
guid: BytesN::from_array(&env, &[nonce as u8; 32]),
|
|
282
|
+
nonce,
|
|
283
|
+
fee: MessagingFee { native_fee, zro_fee },
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/// Helper to check if send was called
|
|
288
|
+
pub fn was_sent(env: Env) -> bool {
|
|
289
|
+
env.storage().instance().get(&symbol_short!("sent")).unwrap_or(false)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/// Get the last destination EID that was sent to
|
|
293
|
+
pub fn get_last_dst_eid(env: Env) -> Option<u32> {
|
|
294
|
+
env.storage().instance().get(&Symbol::new(&env, "last_dst_eid"))
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/// Get the current nonce
|
|
298
|
+
pub fn get_nonce(env: Env) -> u64 {
|
|
299
|
+
env.storage().instance().get(&symbol_short!("nonce")).unwrap_or(0)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/// Implements the send_compose method from MessagingComposer
|
|
303
|
+
pub fn send_compose(env: Env, from: Address, to: Address, guid: BytesN<32>, index: u32, message: Bytes) {
|
|
304
|
+
env.storage().instance().set(&symbol_short!("composed"), &true);
|
|
305
|
+
env.storage().instance().set(&Symbol::new(&env, "compose_from"), &from);
|
|
306
|
+
env.storage().instance().set(&Symbol::new(&env, "compose_to"), &to);
|
|
307
|
+
env.storage().instance().set(&Symbol::new(&env, "compose_guid"), &guid);
|
|
308
|
+
env.storage().instance().set(&Symbol::new(&env, "compose_idx"), &index);
|
|
309
|
+
env.storage().instance().set(&Symbol::new(&env, "compose_msg"), &message);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/// Helper to check if compose was called
|
|
313
|
+
pub fn was_composed(env: Env) -> bool {
|
|
314
|
+
env.storage().instance().get(&symbol_short!("composed")).unwrap_or(false)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
pub fn get_compose_to(env: Env) -> Option<Address> {
|
|
318
|
+
env.storage().instance().get(&Symbol::new(&env, "compose_to"))
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
#[allow(dead_code)]
|
|
322
|
+
pub fn get_compose_msg(env: Env) -> Option<Bytes> {
|
|
323
|
+
env.storage().instance().get(&Symbol::new(&env, "compose_msg"))
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ==================== Test Setup ====================
|
|
328
|
+
|
|
329
|
+
/// Default fees for mock endpoint
|
|
330
|
+
pub const DEFAULT_NATIVE_FEE: i128 = 1000;
|
|
331
|
+
pub const DEFAULT_ZRO_FEE: i128 = 500;
|
|
332
|
+
/// Large amount for pre-minting tokens during setup
|
|
333
|
+
pub const INITIAL_MINT_AMOUNT: i128 = 1_000_000_000_000_000_000;
|
|
334
|
+
|
|
335
|
+
/// OFT strategy type for test setup
|
|
336
|
+
#[derive(Clone, Copy, PartialEq, Eq, Default)]
|
|
337
|
+
pub enum OFTType {
|
|
338
|
+
#[default]
|
|
339
|
+
MintBurn,
|
|
340
|
+
LockUnlock,
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/// Token type for test setup
|
|
344
|
+
#[derive(Clone, Copy, PartialEq, Eq, Default)]
|
|
345
|
+
pub enum TokenType {
|
|
346
|
+
SAC, // Stellar Asset Contract (native, 7 decimals)
|
|
347
|
+
#[default]
|
|
348
|
+
ContractToken, // Custom contract token (configurable decimals)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
pub struct OFTTestSetup<'a> {
|
|
352
|
+
pub env: &'a Env,
|
|
353
|
+
pub oft: OFTClient<'a>,
|
|
354
|
+
pub endpoint_client: MockEndpointWithComposeClient<'a>,
|
|
355
|
+
pub token: Address,
|
|
356
|
+
pub token_client: TokenClient<'a>,
|
|
357
|
+
pub native_token: Address,
|
|
358
|
+
pub zro_token: Address,
|
|
359
|
+
pub owner: Address,
|
|
360
|
+
pub native_fee: i128,
|
|
361
|
+
pub zro_fee: i128,
|
|
362
|
+
pub oft_type: OFTType,
|
|
363
|
+
pub token_decimals: u32,
|
|
364
|
+
pub shared_decimals: u32,
|
|
365
|
+
pub issuer: Address,
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/// Builder for OFTTestSetup
|
|
369
|
+
pub struct OFTTestSetupBuilder<'a> {
|
|
370
|
+
env: &'a Env,
|
|
371
|
+
native_fee: i128,
|
|
372
|
+
zro_fee: i128,
|
|
373
|
+
oft_type: OFTType,
|
|
374
|
+
token_type: TokenType,
|
|
375
|
+
token_decimals: u32,
|
|
376
|
+
shared_decimals: u32,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
impl<'a> OFTTestSetupBuilder<'a> {
|
|
380
|
+
pub fn new(env: &'a Env) -> Self {
|
|
381
|
+
Self {
|
|
382
|
+
env,
|
|
383
|
+
native_fee: DEFAULT_NATIVE_FEE,
|
|
384
|
+
zro_fee: DEFAULT_ZRO_FEE,
|
|
385
|
+
oft_type: OFTType::default(),
|
|
386
|
+
token_type: TokenType::default(),
|
|
387
|
+
token_decimals: 7,
|
|
388
|
+
shared_decimals: DEFAULT_SHARED_DECIMALS,
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
pub fn with_token_decimals(mut self, decimals: u32) -> Self {
|
|
393
|
+
self.token_decimals = decimals;
|
|
394
|
+
// Automatically use ContractToken if custom decimals are requested (SAC is fixed at 7)
|
|
395
|
+
if decimals != 7 {
|
|
396
|
+
self.token_type = TokenType::ContractToken;
|
|
397
|
+
}
|
|
398
|
+
self
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
pub fn with_shared_decimals(mut self, decimals: u32) -> Self {
|
|
402
|
+
self.shared_decimals = decimals;
|
|
403
|
+
self
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
pub fn with_fees(mut self, native_fee: i128, zro_fee: i128) -> Self {
|
|
407
|
+
self.native_fee = native_fee;
|
|
408
|
+
self.zro_fee = zro_fee;
|
|
409
|
+
self
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
pub fn with_native_fee(mut self, native_fee: i128) -> Self {
|
|
413
|
+
self.native_fee = native_fee;
|
|
414
|
+
self
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
pub fn with_zro_fee(mut self, zro_fee: i128) -> Self {
|
|
418
|
+
self.zro_fee = zro_fee;
|
|
419
|
+
self
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
pub fn mint_burn(mut self) -> Self {
|
|
423
|
+
self.oft_type = OFTType::MintBurn;
|
|
424
|
+
self
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
pub fn lock_unlock(mut self) -> Self {
|
|
428
|
+
self.oft_type = OFTType::LockUnlock;
|
|
429
|
+
self
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
pub fn with_sac(mut self) -> Self {
|
|
433
|
+
self.token_type = TokenType::SAC;
|
|
434
|
+
self.token_decimals = 7; // SAC has fixed 7 decimals
|
|
435
|
+
self
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
pub fn with_contract_token(mut self) -> Self {
|
|
439
|
+
self.token_type = TokenType::ContractToken;
|
|
440
|
+
self
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
pub fn build(self) -> OFTTestSetup<'a> {
|
|
444
|
+
let env = self.env;
|
|
445
|
+
let native_fee = self.native_fee;
|
|
446
|
+
let zro_fee = self.zro_fee;
|
|
447
|
+
let oft_type = self.oft_type;
|
|
448
|
+
|
|
449
|
+
let owner = create_recipient_address(env);
|
|
450
|
+
|
|
451
|
+
// Create native token for fees
|
|
452
|
+
let native_sac = env.register_stellar_asset_contract_v2(owner.clone());
|
|
453
|
+
let native_token = native_sac.address();
|
|
454
|
+
|
|
455
|
+
// Create ZRO token
|
|
456
|
+
let zro_sac = env.register_stellar_asset_contract_v2(owner.clone());
|
|
457
|
+
let zro_token = zro_sac.address();
|
|
458
|
+
|
|
459
|
+
// Create OFT token based on token_type
|
|
460
|
+
let (token, actual_token_decimals, issuer) = match self.token_type {
|
|
461
|
+
TokenType::SAC => {
|
|
462
|
+
let sac = env.register_stellar_asset_contract_v2(owner.clone());
|
|
463
|
+
(sac.address(), 7u32, sac.issuer().address()) // SAC has fixed 7 decimals
|
|
464
|
+
}
|
|
465
|
+
TokenType::ContractToken => {
|
|
466
|
+
let token = env.register(DummyToken, (&owner, self.token_decimals));
|
|
467
|
+
(token, self.token_decimals, owner.clone())
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
let token_client = TokenClient::new(env, &token);
|
|
471
|
+
|
|
472
|
+
// Register mock endpoint
|
|
473
|
+
let endpoint_address =
|
|
474
|
+
env.register(MockEndpointWithCompose, (&native_fee, &zro_fee, &native_token, &zro_token));
|
|
475
|
+
let endpoint_client = MockEndpointWithComposeClient::new(env, &endpoint_address);
|
|
476
|
+
|
|
477
|
+
// Register OFT based on type
|
|
478
|
+
let delegate: Option<Address> = Some(owner.clone());
|
|
479
|
+
let oft_address = match oft_type {
|
|
480
|
+
OFTType::MintBurn => env.register(TestMintBurnOFT, (&token, &owner, &endpoint_address, &delegate)),
|
|
481
|
+
OFTType::LockUnlock => env.register(TestLockUnlockOFT, (&token, &owner, &endpoint_address, &delegate)),
|
|
482
|
+
};
|
|
483
|
+
let oft = OFTClient::new(env, &oft_address);
|
|
484
|
+
|
|
485
|
+
// Pre-mint large amounts to owner
|
|
486
|
+
OFTTestSetup::mint_to(env, &owner, &token, &owner, INITIAL_MINT_AMOUNT);
|
|
487
|
+
OFTTestSetup::mint_to(env, &owner, &native_token, &owner, INITIAL_MINT_AMOUNT);
|
|
488
|
+
OFTTestSetup::mint_to(env, &owner, &zro_token, &owner, INITIAL_MINT_AMOUNT);
|
|
489
|
+
|
|
490
|
+
// Setup based on OFT type
|
|
491
|
+
match oft_type {
|
|
492
|
+
OFTType::MintBurn => {
|
|
493
|
+
// Transfer token ownership to OFT so it can burn tokens
|
|
494
|
+
OFTTestSetup::transfer_token_ownership(env, &owner, &token, &oft_address);
|
|
495
|
+
}
|
|
496
|
+
OFTType::LockUnlock => {
|
|
497
|
+
// Fund the OFT with tokens so it can unlock/release them on receive
|
|
498
|
+
OFTTestSetup::mint_to(env, &owner, &token, &oft_address, INITIAL_MINT_AMOUNT);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
log!(&env, "token decimals: {}", self.token_decimals);
|
|
503
|
+
log!(&env, "token address: {}", token);
|
|
504
|
+
log!(&env, "token client: {}", token_client.address);
|
|
505
|
+
log!(&env, "native token address: {}", native_token);
|
|
506
|
+
log!(&env, "zro token address: {}", zro_token);
|
|
507
|
+
log!(&env, "owner: {}", owner);
|
|
508
|
+
log!(&env, "native fee: {}", native_fee);
|
|
509
|
+
log!(&env, "zro fee: {}", zro_fee);
|
|
510
|
+
log!(&env, "oft address: {}", oft_address);
|
|
511
|
+
|
|
512
|
+
OFTTestSetup {
|
|
513
|
+
env,
|
|
514
|
+
oft,
|
|
515
|
+
endpoint_client,
|
|
516
|
+
token,
|
|
517
|
+
token_client,
|
|
518
|
+
native_token,
|
|
519
|
+
zro_token,
|
|
520
|
+
owner,
|
|
521
|
+
native_fee,
|
|
522
|
+
zro_fee,
|
|
523
|
+
oft_type,
|
|
524
|
+
token_decimals: actual_token_decimals,
|
|
525
|
+
shared_decimals: self.shared_decimals,
|
|
526
|
+
issuer,
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
impl<'a> OFTTestSetup<'a> {
|
|
532
|
+
/// Create a new test setup with default configuration (MintBurn OFT)
|
|
533
|
+
pub fn new(env: &'a Env) -> Self {
|
|
534
|
+
OFTTestSetupBuilder::new(env).build()
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/// Create a builder for customized test setup
|
|
538
|
+
pub fn builder(env: &'a Env) -> OFTTestSetupBuilder<'a> {
|
|
539
|
+
OFTTestSetupBuilder::new(env)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/// Returns true if this setup uses a MintBurn OFT
|
|
543
|
+
pub fn is_mint_burn(&self) -> bool {
|
|
544
|
+
self.oft_type == OFTType::MintBurn
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/// Returns true if this setup uses a LockUnlock OFT
|
|
548
|
+
pub fn is_lock_unlock(&self) -> bool {
|
|
549
|
+
self.oft_type == OFTType::LockUnlock
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
pub fn set_peer(&self, eid: u32, peer: &BytesN<32>) {
|
|
553
|
+
self.env.mock_auths(&[MockAuth {
|
|
554
|
+
address: &self.owner,
|
|
555
|
+
invoke: &MockAuthInvoke {
|
|
556
|
+
contract: &self.oft.address,
|
|
557
|
+
fn_name: "set_peer",
|
|
558
|
+
args: (&eid, peer).into_val(self.env),
|
|
559
|
+
sub_invokes: &[],
|
|
560
|
+
},
|
|
561
|
+
}]);
|
|
562
|
+
OAppCoreClient::new(self.env, &self.oft.address).set_peer(&eid, &Some(peer.clone()));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
pub fn mint_to(env: &Env, owner: &Address, token: &Address, to: &Address, amount: i128) {
|
|
566
|
+
env.mock_auths(&[MockAuth {
|
|
567
|
+
address: owner,
|
|
568
|
+
invoke: &MockAuthInvoke {
|
|
569
|
+
contract: token,
|
|
570
|
+
fn_name: "mint",
|
|
571
|
+
args: (to, amount).into_val(env),
|
|
572
|
+
sub_invokes: &[],
|
|
573
|
+
},
|
|
574
|
+
}]);
|
|
575
|
+
StellarAssetClient::new(env, token).mint(to, &amount);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
pub fn transfer_token_ownership(env: &Env, owner: &Address, token: &Address, new_admin: &Address) {
|
|
579
|
+
env.mock_auths(&[MockAuth {
|
|
580
|
+
address: owner,
|
|
581
|
+
invoke: &MockAuthInvoke {
|
|
582
|
+
contract: token,
|
|
583
|
+
fn_name: "set_admin",
|
|
584
|
+
args: (new_admin,).into_val(env),
|
|
585
|
+
sub_invokes: &[],
|
|
586
|
+
},
|
|
587
|
+
}]);
|
|
588
|
+
StellarAssetClient::new(env, token).set_admin(new_admin);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/// Fund an account with native fees only (transfers from owner)
|
|
592
|
+
pub fn fund_native_fees(&self, to: &Address, amount: i128) {
|
|
593
|
+
self.env.mock_auths(&[MockAuth {
|
|
594
|
+
address: &self.owner,
|
|
595
|
+
invoke: &MockAuthInvoke {
|
|
596
|
+
contract: &self.native_token,
|
|
597
|
+
fn_name: "transfer",
|
|
598
|
+
args: (&self.owner, to, amount).into_val(self.env),
|
|
599
|
+
sub_invokes: &[],
|
|
600
|
+
},
|
|
601
|
+
}]);
|
|
602
|
+
TokenClient::new(self.env, &self.native_token).transfer(&self.owner, to, &amount);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/// Fund an account with ZRO fees (transfers from owner)
|
|
606
|
+
pub fn fund_zro_fees(&self, to: &Address, amount: i128) {
|
|
607
|
+
self.env.mock_auths(&[MockAuth {
|
|
608
|
+
address: &self.owner,
|
|
609
|
+
invoke: &MockAuthInvoke {
|
|
610
|
+
contract: &self.zro_token,
|
|
611
|
+
fn_name: "transfer",
|
|
612
|
+
args: (&self.owner, to, amount).into_val(self.env),
|
|
613
|
+
sub_invokes: &[],
|
|
614
|
+
},
|
|
615
|
+
}]);
|
|
616
|
+
TokenClient::new(self.env, &self.zro_token).transfer(&self.owner, to, &amount);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/// Fund an account with OFT tokens only (transfers from owner)
|
|
620
|
+
pub fn fund_tokens(&self, to: &Address, amount: i128) {
|
|
621
|
+
self.env.mock_auths(&[MockAuth {
|
|
622
|
+
address: &self.owner,
|
|
623
|
+
invoke: &MockAuthInvoke {
|
|
624
|
+
contract: &self.token,
|
|
625
|
+
fn_name: "transfer",
|
|
626
|
+
args: (&self.owner, to, amount).into_val(self.env),
|
|
627
|
+
sub_invokes: &[],
|
|
628
|
+
},
|
|
629
|
+
}]);
|
|
630
|
+
self.token_client.transfer(&self.owner, to, &amount);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/// Quote OFT to get the receipt for authorization
|
|
634
|
+
pub fn quote_oft(&self, send_param: &SendParam) -> OFTReceipt {
|
|
635
|
+
let (_, _, receipt) = self.oft.quote_oft(send_param);
|
|
636
|
+
receipt
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/// Send tokens cross-chain with proper sender authentication
|
|
640
|
+
pub fn send(
|
|
641
|
+
&self,
|
|
642
|
+
sender: &Address,
|
|
643
|
+
send_param: &SendParam,
|
|
644
|
+
fee: &MessagingFee,
|
|
645
|
+
refund_address: &Address,
|
|
646
|
+
oft_receipt: &OFTReceipt,
|
|
647
|
+
) -> (MessagingReceipt, OFTReceipt) {
|
|
648
|
+
// Token operation sub-invoke differs based on OFT type
|
|
649
|
+
let token_sub_invoke = match self.oft_type {
|
|
650
|
+
OFTType::MintBurn => MockAuthInvoke {
|
|
651
|
+
contract: &self.token,
|
|
652
|
+
fn_name: "burn",
|
|
653
|
+
args: (sender, &oft_receipt.amount_sent_ld).into_val(self.env),
|
|
654
|
+
sub_invokes: &[],
|
|
655
|
+
},
|
|
656
|
+
OFTType::LockUnlock => MockAuthInvoke {
|
|
657
|
+
contract: &self.token,
|
|
658
|
+
fn_name: "transfer",
|
|
659
|
+
args: (sender, &self.oft.address, &oft_receipt.amount_sent_ld).into_val(self.env),
|
|
660
|
+
sub_invokes: &[],
|
|
661
|
+
},
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
self.env.mock_auths(&[MockAuth {
|
|
665
|
+
address: sender,
|
|
666
|
+
invoke: &MockAuthInvoke {
|
|
667
|
+
contract: &self.oft.address,
|
|
668
|
+
fn_name: "send",
|
|
669
|
+
args: (sender, send_param, fee, refund_address).into_val(self.env),
|
|
670
|
+
sub_invokes: &[
|
|
671
|
+
MockAuthInvoke {
|
|
672
|
+
contract: &self.native_token,
|
|
673
|
+
fn_name: "transfer",
|
|
674
|
+
args: (sender, &self.endpoint_client.address, &fee.native_fee).into_val(self.env),
|
|
675
|
+
sub_invokes: &[],
|
|
676
|
+
},
|
|
677
|
+
MockAuthInvoke {
|
|
678
|
+
contract: &self.zro_token,
|
|
679
|
+
fn_name: "transfer",
|
|
680
|
+
args: (sender, &self.endpoint_client.address, &fee.zro_fee).into_val(self.env),
|
|
681
|
+
sub_invokes: &[],
|
|
682
|
+
},
|
|
683
|
+
token_sub_invoke,
|
|
684
|
+
],
|
|
685
|
+
},
|
|
686
|
+
}]);
|
|
687
|
+
self.oft.send(sender, send_param, fee, refund_address)
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/// Try send tokens cross-chain with proper sender authentication (returns Result)
|
|
691
|
+
pub fn try_send(
|
|
692
|
+
&self,
|
|
693
|
+
sender: &Address,
|
|
694
|
+
send_param: &SendParam,
|
|
695
|
+
fee: &MessagingFee,
|
|
696
|
+
refund_address: &Address,
|
|
697
|
+
oft_receipt: &OFTReceipt,
|
|
698
|
+
) -> Result<
|
|
699
|
+
Result<(MessagingReceipt, OFTReceipt), soroban_sdk::Error>,
|
|
700
|
+
Result<soroban_sdk::Error, soroban_sdk::InvokeError>,
|
|
701
|
+
> {
|
|
702
|
+
// Token operation sub-invoke differs based on OFT type
|
|
703
|
+
let token_sub_invoke = match self.oft_type {
|
|
704
|
+
OFTType::MintBurn => MockAuthInvoke {
|
|
705
|
+
contract: &self.token,
|
|
706
|
+
fn_name: "burn",
|
|
707
|
+
args: (sender, &oft_receipt.amount_sent_ld).into_val(self.env),
|
|
708
|
+
sub_invokes: &[],
|
|
709
|
+
},
|
|
710
|
+
OFTType::LockUnlock => MockAuthInvoke {
|
|
711
|
+
contract: &self.token,
|
|
712
|
+
fn_name: "transfer",
|
|
713
|
+
args: (sender, &self.oft.address, &oft_receipt.amount_sent_ld).into_val(self.env),
|
|
714
|
+
sub_invokes: &[],
|
|
715
|
+
},
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
self.env.mock_auths(&[MockAuth {
|
|
719
|
+
address: sender,
|
|
720
|
+
invoke: &MockAuthInvoke {
|
|
721
|
+
contract: &self.oft.address,
|
|
722
|
+
fn_name: "send",
|
|
723
|
+
args: (sender, send_param, fee, refund_address).into_val(self.env),
|
|
724
|
+
sub_invokes: &[
|
|
725
|
+
MockAuthInvoke {
|
|
726
|
+
contract: &self.native_token,
|
|
727
|
+
fn_name: "transfer",
|
|
728
|
+
args: (sender, &self.endpoint_client.address, &fee.native_fee).into_val(self.env),
|
|
729
|
+
sub_invokes: &[],
|
|
730
|
+
},
|
|
731
|
+
MockAuthInvoke {
|
|
732
|
+
contract: &self.zro_token,
|
|
733
|
+
fn_name: "transfer",
|
|
734
|
+
args: (sender, &self.endpoint_client.address, &fee.zro_fee).into_val(self.env),
|
|
735
|
+
sub_invokes: &[],
|
|
736
|
+
},
|
|
737
|
+
token_sub_invoke,
|
|
738
|
+
],
|
|
739
|
+
},
|
|
740
|
+
}]);
|
|
741
|
+
self.oft.try_send(sender, send_param, fee, refund_address)
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/// Execute lz_receive with proper executor authentication
|
|
745
|
+
pub fn lz_receive(
|
|
746
|
+
&self,
|
|
747
|
+
executor: &Address,
|
|
748
|
+
origin: &Origin,
|
|
749
|
+
guid: &BytesN<32>,
|
|
750
|
+
message: &Bytes,
|
|
751
|
+
extra_data: &Bytes,
|
|
752
|
+
value: i128,
|
|
753
|
+
) {
|
|
754
|
+
self.env.mock_auths(&[MockAuth {
|
|
755
|
+
address: executor,
|
|
756
|
+
invoke: &MockAuthInvoke {
|
|
757
|
+
contract: &self.oft.address,
|
|
758
|
+
fn_name: "lz_receive",
|
|
759
|
+
args: (executor, origin, guid, message, extra_data, value).into_val(self.env),
|
|
760
|
+
sub_invokes: &[],
|
|
761
|
+
},
|
|
762
|
+
}]);
|
|
763
|
+
LayerZeroReceiverClient::new(self.env, &self.oft.address)
|
|
764
|
+
.lz_receive(executor, origin, guid, message, extra_data, &value);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/// Try lz_receive with proper executor authentication (returns Result)
|
|
768
|
+
pub fn try_lz_receive(
|
|
769
|
+
&self,
|
|
770
|
+
executor: &Address,
|
|
771
|
+
origin: &Origin,
|
|
772
|
+
guid: &BytesN<32>,
|
|
773
|
+
message: &Bytes,
|
|
774
|
+
extra_data: &Bytes,
|
|
775
|
+
value: i128,
|
|
776
|
+
) -> Result<Result<(), soroban_sdk::ConversionError>, Result<soroban_sdk::Error, soroban_sdk::InvokeError>> {
|
|
777
|
+
self.env.mock_auths(&[MockAuth {
|
|
778
|
+
address: executor,
|
|
779
|
+
invoke: &MockAuthInvoke {
|
|
780
|
+
contract: &self.oft.address,
|
|
781
|
+
fn_name: "lz_receive",
|
|
782
|
+
args: (executor, origin, guid, message, extra_data, value).into_val(self.env),
|
|
783
|
+
sub_invokes: &[],
|
|
784
|
+
},
|
|
785
|
+
}]);
|
|
786
|
+
LayerZeroReceiverClient::new(self.env, &self.oft.address)
|
|
787
|
+
.try_lz_receive(executor, origin, guid, message, extra_data, &value)
|
|
788
|
+
}
|
|
789
|
+
}
|