@layerzerolabs/protocol-stellar-v2 0.2.8
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 +727 -0
- package/.turbo/turbo-lint.log +158 -0
- package/.turbo/turbo-test.log +796 -0
- package/Cargo.lock +2237 -0
- package/Cargo.toml +63 -0
- package/clippy.toml +7 -0
- package/contracts/common-macros/Cargo.toml +20 -0
- package/contracts/common-macros/src/error.rs +53 -0
- package/contracts/common-macros/src/event.rs +16 -0
- package/contracts/common-macros/src/lib.rs +255 -0
- package/contracts/common-macros/src/ownable.rs +63 -0
- package/contracts/common-macros/src/snapshots/common_macros__tests__tests__snapshot_generated_storage_code.snap +310 -0
- package/contracts/common-macros/src/storage.rs +439 -0
- package/contracts/common-macros/src/tests.rs +287 -0
- package/contracts/common-macros/src/ttl_configurable.rs +60 -0
- package/contracts/endpoint-v2/ARCHITECTURE.md +233 -0
- package/contracts/endpoint-v2/Cargo.toml +30 -0
- package/contracts/endpoint-v2/src/constants.rs +52 -0
- package/contracts/endpoint-v2/src/endpoint_v2.rs +305 -0
- package/contracts/endpoint-v2/src/errors.rs +29 -0
- package/contracts/endpoint-v2/src/events.rs +207 -0
- package/contracts/endpoint-v2/src/interfaces/layerzero_composer.rs +26 -0
- package/contracts/endpoint-v2/src/interfaces/layerzero_endpoint_v2.rs +170 -0
- package/contracts/endpoint-v2/src/interfaces/layerzero_receiver.rs +43 -0
- package/contracts/endpoint-v2/src/interfaces/message_lib.rs +62 -0
- package/contracts/endpoint-v2/src/interfaces/message_lib_manager.rs +220 -0
- package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +121 -0
- package/contracts/endpoint-v2/src/interfaces/messaging_composer.rs +63 -0
- package/contracts/endpoint-v2/src/interfaces/mod.rs +17 -0
- package/contracts/endpoint-v2/src/interfaces/send_lib.rs +70 -0
- package/contracts/endpoint-v2/src/lib.rs +22 -0
- package/contracts/endpoint-v2/src/message_lib_manager.rs +315 -0
- package/contracts/endpoint-v2/src/messaging_channel.rs +218 -0
- package/contracts/endpoint-v2/src/messaging_composer.rs +76 -0
- package/contracts/endpoint-v2/src/storage.rs +78 -0
- package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +131 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +237 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/delegate.rs +42 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/initializable.rs +76 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +211 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/mod.rs +18 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/native_token.rs +10 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/owner.rs +10 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +424 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/quote.rs +144 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/recover_token.rs +72 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/require_oapp_auth.rs +29 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +513 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +43 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +27 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/transfer_ownership.rs +30 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/ttl_config.rs +202 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +59 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +172 -0
- package/contracts/endpoint-v2/src/tests/endpoint_v2/zro.rs +23 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/mod.rs +10 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +131 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/require_registered.rs +35 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/require_supported_eid.rs +28 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_config.rs +79 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +246 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +285 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +180 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +405 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +80 -0
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +131 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +358 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/clear.rs +316 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_nonce.rs +288 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_payload_hash.rs +316 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/internal.rs +388 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/lazy_inbound_nonce.rs +307 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +10 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/next_guid.rs +239 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +324 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/outbound_nonce.rs +242 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +232 -0
- package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +212 -0
- package/contracts/endpoint-v2/src/tests/messaging_composer/compose_queue.rs +213 -0
- package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +269 -0
- package/contracts/endpoint-v2/src/tests/messaging_composer/mod.rs +4 -0
- package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +173 -0
- package/contracts/endpoint-v2/src/tests/mock.rs +132 -0
- package/contracts/endpoint-v2/src/tests/mod.rs +12 -0
- package/contracts/endpoint-v2/src/tests/util/build_payload.rs +126 -0
- package/contracts/endpoint-v2/src/tests/util/compute_guid.rs +82 -0
- package/contracts/endpoint-v2/src/tests/util/keccak256.rs +115 -0
- package/contracts/endpoint-v2/src/tests/util/mod.rs +3 -0
- package/contracts/endpoint-v2/src/util.rs +52 -0
- package/contracts/message-libs/Cargo.toml +12 -0
- package/contracts/message-libs/block-message-lib/Cargo.toml +19 -0
- package/contracts/message-libs/block-message-lib/src/lib.rs +70 -0
- package/contracts/message-libs/lib.rs +2 -0
- package/contracts/message-libs/message-lib-common/Cargo.toml +24 -0
- package/contracts/message-libs/message-lib-common/src/errors.rs +20 -0
- package/contracts/message-libs/message-lib-common/src/interfaces/dvn.rs +55 -0
- package/contracts/message-libs/message-lib-common/src/interfaces/executor.rs +46 -0
- package/contracts/message-libs/message-lib-common/src/interfaces/mod.rs +7 -0
- package/contracts/message-libs/message-lib-common/src/interfaces/treasury.rs +17 -0
- package/contracts/message-libs/message-lib-common/src/lib.rs +14 -0
- package/contracts/message-libs/message-lib-common/src/packet_codec_v1.rs +99 -0
- package/contracts/message-libs/message-lib-common/src/testing_utils.rs +27 -0
- package/contracts/message-libs/message-lib-common/src/tests/mod.rs +2 -0
- package/contracts/message-libs/message-lib-common/src/tests/packet_codec_v1.rs +162 -0
- package/contracts/message-libs/message-lib-common/src/tests/worker_options.rs +319 -0
- package/contracts/message-libs/message-lib-common/src/worker_options.rs +190 -0
- package/contracts/message-libs/simple-message-lib/Cargo.toml +26 -0
- package/contracts/message-libs/simple-message-lib/src/errors.rs +11 -0
- package/contracts/message-libs/simple-message-lib/src/lib.rs +14 -0
- package/contracts/message-libs/simple-message-lib/src/simple_message_lib.rs +136 -0
- package/contracts/message-libs/simple-message-lib/src/storage.rs +27 -0
- package/contracts/message-libs/simple-message-lib/src/test.rs +280 -0
- package/contracts/message-libs/treasury/Cargo.toml +27 -0
- package/contracts/message-libs/treasury/src/errors.rs +10 -0
- package/contracts/message-libs/treasury/src/events.rs +28 -0
- package/contracts/message-libs/treasury/src/interfaces/mod.rs +3 -0
- package/contracts/message-libs/treasury/src/interfaces/zro_fee_lib.rs +20 -0
- package/contracts/message-libs/treasury/src/lib.rs +20 -0
- package/contracts/message-libs/treasury/src/storage.rs +18 -0
- package/contracts/message-libs/treasury/src/tests/mod.rs +2 -0
- package/contracts/message-libs/treasury/src/tests/setup.rs +112 -0
- package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +562 -0
- package/contracts/message-libs/treasury/src/treasury.rs +140 -0
- package/contracts/message-libs/uln-302/Cargo.toml +28 -0
- package/contracts/message-libs/uln-302/src/config_validation.rs +173 -0
- package/contracts/message-libs/uln-302/src/errors.rs +29 -0
- package/contracts/message-libs/uln-302/src/events.rs +72 -0
- package/contracts/message-libs/uln-302/src/interfaces/mod.rs +5 -0
- package/contracts/message-libs/uln-302/src/interfaces/receive.rs +82 -0
- package/contracts/message-libs/uln-302/src/interfaces/send.rs +159 -0
- package/contracts/message-libs/uln-302/src/lib.rs +20 -0
- package/contracts/message-libs/uln-302/src/receive.rs +199 -0
- package/contracts/message-libs/uln-302/src/send.rs +349 -0
- package/contracts/message-libs/uln-302/src/storage.rs +47 -0
- package/contracts/message-libs/uln-302/src/tests/config/mod.rs +2 -0
- package/contracts/message-libs/uln-302/src/tests/config/oapp_uln_config.rs +291 -0
- package/contracts/message-libs/uln-302/src/tests/config/uln_config.rs +163 -0
- package/contracts/message-libs/uln-302/src/tests/mod.rs +7 -0
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/commit_verification.rs +183 -0
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/confirmations.rs +128 -0
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +104 -0
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/mod.rs +66 -0
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +79 -0
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/verifiable.rs +463 -0
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +173 -0
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +132 -0
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +117 -0
- package/contracts/message-libs/uln-302/src/tests/send_uln302/mod.rs +6 -0
- package/contracts/message-libs/uln-302/src/tests/send_uln302/quote.rs +586 -0
- package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +834 -0
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +95 -0
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +80 -0
- package/contracts/message-libs/uln-302/src/tests/setup.rs +268 -0
- package/contracts/message-libs/uln-302/src/tests/testing_utils.rs +47 -0
- package/contracts/message-libs/uln-302/src/tests/uln302/get_app_receive_uln_config.rs +51 -0
- package/contracts/message-libs/uln-302/src/tests/uln302/get_app_send_uln_config.rs +51 -0
- package/contracts/message-libs/uln-302/src/tests/uln302/get_oapp_executor_config.rs +48 -0
- package/contracts/message-libs/uln-302/src/tests/uln302/mod.rs +4 -0
- package/contracts/message-libs/uln-302/src/tests/uln302/set_config.rs +998 -0
- package/contracts/message-libs/uln-302/src/uln302.rs +117 -0
- package/contracts/oapp-macros/Cargo.toml +21 -0
- package/contracts/oapp-macros/src/lib.rs +408 -0
- package/contracts/oapp-macros/src/oapp_core.rs +49 -0
- package/contracts/oapp-macros/src/oapp_full.rs +15 -0
- package/contracts/oapp-macros/src/oapp_options_type3.rs +46 -0
- package/contracts/oapp-macros/src/oapp_receiver.rs +67 -0
- package/contracts/oapp-macros/src/oapp_sender.rs +23 -0
- package/contracts/oapp-macros/src/util.rs +103 -0
- package/contracts/oapp-macros/tests/test_macros.rs +522 -0
- package/contracts/oapps/Cargo.toml +12 -0
- package/contracts/oapps/counter/Cargo.toml +24 -0
- package/contracts/oapps/counter/integration_tests/mod.rs +3 -0
- package/contracts/oapps/counter/integration_tests/setup.rs +201 -0
- package/contracts/oapps/counter/integration_tests/test_with_sml.rs +166 -0
- package/contracts/oapps/counter/integration_tests/utils.rs +144 -0
- package/contracts/oapps/counter/src/codec.rs +63 -0
- package/contracts/oapps/counter/src/counter.rs +235 -0
- package/contracts/oapps/counter/src/errors.rs +9 -0
- package/contracts/oapps/counter/src/lib.rs +16 -0
- package/contracts/oapps/counter/src/options.rs +30 -0
- package/contracts/oapps/counter/src/storage.rs +33 -0
- package/contracts/oapps/counter/src/tests/mod.rs +37 -0
- package/contracts/oapps/counter/src/tests/test_codec.rs +64 -0
- package/contracts/oapps/counter/src/tests/test_counter.rs +390 -0
- package/contracts/oapps/counter/src/u256_ext.rs +21 -0
- package/contracts/oapps/lib.rs +2 -0
- package/contracts/oapps/oapp/Cargo.toml +21 -0
- package/contracts/oapps/oapp/src/errors.rs +9 -0
- package/contracts/oapps/oapp/src/lib.rs +10 -0
- package/contracts/oapps/oapp/src/oapp_core.rs +92 -0
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +89 -0
- package/contracts/oapps/oapp/src/oapp_receiver.rs +72 -0
- package/contracts/oapps/oapp/src/oapp_sender.rs +66 -0
- package/contracts/oapps/oapp/src/tests/mod.rs +4 -0
- package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +162 -0
- package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +180 -0
- package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +157 -0
- package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +283 -0
- package/contracts/utils/Cargo.toml +21 -0
- package/contracts/utils/src/buffer_reader.rs +143 -0
- package/contracts/utils/src/buffer_writer.rs +117 -0
- package/contracts/utils/src/bytes_ext.rs +19 -0
- package/contracts/utils/src/errors.rs +30 -0
- package/contracts/utils/src/lib.rs +15 -0
- package/contracts/utils/src/option_ext.rs +38 -0
- package/contracts/utils/src/ownable.rs +88 -0
- package/contracts/utils/src/testing_utils.rs +100 -0
- package/contracts/utils/src/tests/buffer_reader.rs +1006 -0
- package/contracts/utils/src/tests/buffer_writer.rs +330 -0
- package/contracts/utils/src/tests/bytes_ext.rs +77 -0
- package/contracts/utils/src/tests/mod.rs +4 -0
- package/contracts/utils/src/tests/ownable.rs +149 -0
- package/contracts/utils/src/ttl.rs +164 -0
- package/contracts/workers/Cargo.toml +13 -0
- package/contracts/workers/executor/Cargo.toml +26 -0
- package/contracts/workers/executor/src/events.rs +22 -0
- package/contracts/workers/executor/src/executor.rs +347 -0
- package/contracts/workers/executor/src/interfaces/executor.rs +40 -0
- package/contracts/workers/executor/src/interfaces/mod.rs +5 -0
- package/contracts/workers/executor/src/interfaces/types.rs +51 -0
- package/contracts/workers/executor/src/lib.rs +10 -0
- package/contracts/workers/executor/src/storage.rs +23 -0
- package/contracts/workers/lib.rs +2 -0
- package/contracts/workers/worker-common/Cargo.toml +18 -0
- package/contracts/workers/worker-common/src/constants.rs +17 -0
- package/contracts/workers/worker-common/src/errors.rs +6 -0
- package/contracts/workers/worker-common/src/events.rs +34 -0
- package/contracts/workers/worker-common/src/interfaces/executor_fee_lib.rs +35 -0
- package/contracts/workers/worker-common/src/interfaces/mod.rs +7 -0
- package/contracts/workers/worker-common/src/interfaces/price_feed.rs +40 -0
- package/contracts/workers/worker-common/src/interfaces/worker.rs +60 -0
- package/contracts/workers/worker-common/src/lib.rs +19 -0
- package/contracts/workers/worker-common/src/storage.rs +32 -0
- package/contracts/workers/worker-common/src/worker_common.rs +166 -0
- package/package.json +25 -0
- package/rust-toolchain.toml +4 -0
- package/rustfmt.toml +17 -0
- package/sdk/.turbo/turbo-build.log +4 -0
- package/sdk/dist/generated/bml.d.ts +452 -0
- package/sdk/dist/generated/bml.js +72 -0
- package/sdk/dist/generated/counter.d.ts +824 -0
- package/sdk/dist/generated/counter.js +125 -0
- package/sdk/dist/generated/endpoint.d.ts +1676 -0
- package/sdk/dist/generated/endpoint.js +216 -0
- package/sdk/dist/generated/sml.d.ts +810 -0
- package/sdk/dist/generated/sml.js +132 -0
- package/sdk/dist/generated/uln302.d.ts +1227 -0
- package/sdk/dist/generated/uln302.js +185 -0
- package/sdk/dist/index.d.ts +5 -0
- package/sdk/dist/index.js +5 -0
- package/sdk/node_modules/.bin/tsc +21 -0
- package/sdk/node_modules/.bin/tsserver +21 -0
- package/sdk/node_modules/.bin/vitest +21 -0
- package/sdk/node_modules/.bin/zx +21 -0
- package/sdk/package.json +40 -0
- package/sdk/src/index.ts +5 -0
- package/sdk/test/index.test.ts +271 -0
- package/sdk/test/suites/constants.ts +13 -0
- package/sdk/test/suites/deploy.ts +277 -0
- package/sdk/test/suites/localnet.ts +42 -0
- package/sdk/test/suites/scan.ts +189 -0
- package/sdk/tsconfig.json +106 -0
- package/tools/ts-bindings-gen/Cargo.toml +14 -0
- package/tools/ts-bindings-gen/src/main.rs +147 -0
- package/turbo.json +12 -0
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
extern crate std;
|
|
2
|
+
|
|
3
|
+
use soroban_sdk::testutils::{Address as _, Events as _};
|
|
4
|
+
|
|
5
|
+
use crate::{
|
|
6
|
+
errors::TreasuryError,
|
|
7
|
+
tests::setup::{setup, BPS_DENOMINATOR},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Initialization Tests
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
#[test]
|
|
15
|
+
fn test_treasury_initialization() {
|
|
16
|
+
let setup = setup();
|
|
17
|
+
|
|
18
|
+
// Verify initial state matches defaults
|
|
19
|
+
assert_eq!(setup.treasury.native_fee_bp(), 0);
|
|
20
|
+
assert!(!setup.treasury.fee_enabled());
|
|
21
|
+
assert!(setup.treasury.zro_fee_lib().is_none());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Core Fee Logic Tests
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
#[test]
|
|
29
|
+
fn test_get_fee_disabled_by_default() {
|
|
30
|
+
let setup = setup();
|
|
31
|
+
|
|
32
|
+
let sender = soroban_sdk::Address::generate(&setup.env);
|
|
33
|
+
let dst_eid = 101_u32;
|
|
34
|
+
|
|
35
|
+
// When fee_enabled = false, should return 0 regardless of other settings
|
|
36
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &1000, &false);
|
|
37
|
+
assert_eq!(fee, 0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#[test]
|
|
41
|
+
fn test_get_fee_native_payment_enabled() {
|
|
42
|
+
let setup = setup();
|
|
43
|
+
|
|
44
|
+
let sender = soroban_sdk::Address::generate(&setup.env);
|
|
45
|
+
let dst_eid = 101_u32;
|
|
46
|
+
|
|
47
|
+
// Configure treasury with 5% native fee (500 BPS)
|
|
48
|
+
setup.configure_treasury(500);
|
|
49
|
+
|
|
50
|
+
// Test various amounts
|
|
51
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &1000, &false);
|
|
52
|
+
assert_eq!(fee, 50); // 1000 * 500 / 10000 = 50
|
|
53
|
+
|
|
54
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &10000, &false);
|
|
55
|
+
assert_eq!(fee, 500); // 10000 * 500 / 10000 = 500
|
|
56
|
+
|
|
57
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &0, &false);
|
|
58
|
+
assert_eq!(fee, 0); // 0 * 500 / 10000 = 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#[test]
|
|
62
|
+
fn test_get_fee_zro_payment_requires_fee_lib() {
|
|
63
|
+
let setup = setup();
|
|
64
|
+
|
|
65
|
+
let sender = soroban_sdk::Address::generate(&setup.env);
|
|
66
|
+
let dst_eid = 101_u32;
|
|
67
|
+
|
|
68
|
+
// Configure treasury without ZRO fee lib
|
|
69
|
+
setup.configure_treasury(500);
|
|
70
|
+
|
|
71
|
+
// Should fail when trying to pay in ZRO without fee lib set
|
|
72
|
+
let result = setup.treasury.try_get_fee(&sender, &dst_eid, &1000, &true);
|
|
73
|
+
assert_eq!(result.err().unwrap().ok().unwrap(), TreasuryError::ZROFeeLibNotSet.into());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ============================================================================
|
|
77
|
+
// Admin Configuration Tests
|
|
78
|
+
// ============================================================================
|
|
79
|
+
|
|
80
|
+
#[test]
|
|
81
|
+
fn test_set_fee_enabled() {
|
|
82
|
+
let setup = setup();
|
|
83
|
+
|
|
84
|
+
// Initially disabled
|
|
85
|
+
assert!(!setup.treasury.fee_enabled());
|
|
86
|
+
|
|
87
|
+
// Enable fees
|
|
88
|
+
setup.mock_owner_auth("set_fee_enabled", (&true,));
|
|
89
|
+
setup.treasury.set_fee_enabled(&true);
|
|
90
|
+
assert!(setup.treasury.fee_enabled());
|
|
91
|
+
|
|
92
|
+
// Disable fees again
|
|
93
|
+
setup.mock_owner_auth("set_fee_enabled", (&false,));
|
|
94
|
+
setup.treasury.set_fee_enabled(&false);
|
|
95
|
+
assert!(!setup.treasury.fee_enabled());
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#[test]
|
|
99
|
+
fn test_set_native_fee_bp() {
|
|
100
|
+
let setup = setup();
|
|
101
|
+
|
|
102
|
+
// Test valid BPS values
|
|
103
|
+
setup.mock_owner_auth("set_native_fee_bp", (&0_u32,));
|
|
104
|
+
setup.treasury.set_native_fee_bp(&0);
|
|
105
|
+
assert_eq!(setup.treasury.native_fee_bp(), 0);
|
|
106
|
+
|
|
107
|
+
setup.mock_owner_auth("set_native_fee_bp", (&500_u32,));
|
|
108
|
+
setup.treasury.set_native_fee_bp(&500); // 5%
|
|
109
|
+
assert_eq!(setup.treasury.native_fee_bp(), 500);
|
|
110
|
+
|
|
111
|
+
setup.mock_owner_auth("set_native_fee_bp", (&10000_u32,));
|
|
112
|
+
setup.treasury.set_native_fee_bp(&10000); // 100%
|
|
113
|
+
assert_eq!(setup.treasury.native_fee_bp(), 10000);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#[test]
|
|
117
|
+
fn test_set_native_fee_bp_invalid() {
|
|
118
|
+
let setup = setup();
|
|
119
|
+
|
|
120
|
+
// Should fail with BPS > 10000
|
|
121
|
+
setup.mock_owner_auth("set_native_fee_bp", (&10001_u32,));
|
|
122
|
+
let result = setup.treasury.try_set_native_fee_bp(&10001);
|
|
123
|
+
assert_eq!(result.err().unwrap().ok().unwrap(), TreasuryError::InvalidNativeFeeBp.into());
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#[test]
|
|
127
|
+
fn test_set_zro_fee_lib() {
|
|
128
|
+
let setup = setup();
|
|
129
|
+
|
|
130
|
+
// Use contract address since it needs to pass .exists() check
|
|
131
|
+
let fee_lib = setup.create_contract_address();
|
|
132
|
+
|
|
133
|
+
// Initially no fee lib
|
|
134
|
+
assert!(setup.treasury.zro_fee_lib().is_none());
|
|
135
|
+
|
|
136
|
+
// Set fee lib
|
|
137
|
+
setup.mock_owner_auth("set_zro_fee_lib", (&Some(fee_lib.clone()),));
|
|
138
|
+
setup.treasury.set_zro_fee_lib(&Some(fee_lib.clone()));
|
|
139
|
+
assert_eq!(setup.treasury.zro_fee_lib(), Some(fee_lib));
|
|
140
|
+
|
|
141
|
+
// Remove fee lib
|
|
142
|
+
let none_val: Option<soroban_sdk::Address> = None;
|
|
143
|
+
setup.mock_owner_auth("set_zro_fee_lib", (&none_val,));
|
|
144
|
+
setup.treasury.set_zro_fee_lib(&none_val);
|
|
145
|
+
assert!(setup.treasury.zro_fee_lib().is_none());
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
#[test]
|
|
149
|
+
fn test_set_zro_fee_lib_invalid_address() {
|
|
150
|
+
let setup = setup();
|
|
151
|
+
|
|
152
|
+
// Generate an address that doesn't exist (won't pass .exists() check)
|
|
153
|
+
let non_existent_lib = soroban_sdk::Address::generate(&setup.env);
|
|
154
|
+
|
|
155
|
+
// Try to set non-existent fee lib
|
|
156
|
+
setup.mock_owner_auth("set_zro_fee_lib", (&Some(non_existent_lib.clone()),));
|
|
157
|
+
let result = setup.treasury.try_set_zro_fee_lib(&Some(non_existent_lib));
|
|
158
|
+
assert_eq!(result.err().unwrap().ok().unwrap(), TreasuryError::InvalidZROFeeLib.into());
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ============================================================================
|
|
162
|
+
// Edge Cases & Boundary Tests
|
|
163
|
+
// ============================================================================
|
|
164
|
+
|
|
165
|
+
#[test]
|
|
166
|
+
fn test_fee_calculation_edge_cases() {
|
|
167
|
+
let setup = setup();
|
|
168
|
+
|
|
169
|
+
let sender = soroban_sdk::Address::generate(&setup.env);
|
|
170
|
+
let dst_eid = 101_u32;
|
|
171
|
+
|
|
172
|
+
setup.configure_treasury(0);
|
|
173
|
+
|
|
174
|
+
// Test 0% fee (0 BPS)
|
|
175
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &1000, &false);
|
|
176
|
+
assert_eq!(fee, 0);
|
|
177
|
+
|
|
178
|
+
// Test 100% fee (10000 BPS)
|
|
179
|
+
setup.mock_owner_auth("set_native_fee_bp", (&10000_u32,));
|
|
180
|
+
setup.treasury.set_native_fee_bp(&10000);
|
|
181
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &1000, &false);
|
|
182
|
+
assert_eq!(fee, 1000); // 1000 * 10000 / 10000 = 1000
|
|
183
|
+
|
|
184
|
+
// Test maximum total fee with minimal BPS
|
|
185
|
+
let max_safe_input: i128 = i128::MAX / BPS_DENOMINATOR as i128; // Avoid overflow
|
|
186
|
+
setup.mock_owner_auth("set_native_fee_bp", (&1_u32,));
|
|
187
|
+
setup.treasury.set_native_fee_bp(&1); // 0.01%
|
|
188
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &max_safe_input, &false);
|
|
189
|
+
assert_eq!(fee, max_safe_input / BPS_DENOMINATOR as i128);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
#[test]
|
|
193
|
+
fn test_precision_and_rounding() {
|
|
194
|
+
let setup = setup();
|
|
195
|
+
|
|
196
|
+
let sender = soroban_sdk::Address::generate(&setup.env);
|
|
197
|
+
let dst_eid = 101_u32;
|
|
198
|
+
|
|
199
|
+
setup.configure_treasury(1); // 0.01%
|
|
200
|
+
|
|
201
|
+
// Test rounding behavior (integer division truncates)
|
|
202
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &9999, &false);
|
|
203
|
+
assert_eq!(fee, 0); // 9999 * 1 / 10000 = 0 (rounded down)
|
|
204
|
+
|
|
205
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &10000, &false);
|
|
206
|
+
assert_eq!(fee, 1); // 10000 * 1 / 10000 = 1
|
|
207
|
+
|
|
208
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &20000, &false);
|
|
209
|
+
assert_eq!(fee, 2); // 20000 * 1 / 10000 = 2
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#[test]
|
|
213
|
+
fn test_get_fee_rejects_negative_total_native_fee() {
|
|
214
|
+
let setup = setup();
|
|
215
|
+
|
|
216
|
+
let sender = soroban_sdk::Address::generate(&setup.env);
|
|
217
|
+
let dst_eid = 101_u32;
|
|
218
|
+
|
|
219
|
+
setup.configure_treasury(500);
|
|
220
|
+
|
|
221
|
+
let result = setup.treasury.try_get_fee(&sender, &dst_eid, &(-1_i128), &false);
|
|
222
|
+
assert_eq!(result.err().unwrap().ok().unwrap(), TreasuryError::InvalidTotalNativeFee.into());
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// Withdraw Token Tests
|
|
227
|
+
// ============================================================================
|
|
228
|
+
|
|
229
|
+
#[test]
|
|
230
|
+
fn test_withdraw_token_valid() {
|
|
231
|
+
let setup = setup();
|
|
232
|
+
|
|
233
|
+
// Create recipient address (must exist)
|
|
234
|
+
let recipient = setup.create_contract_address();
|
|
235
|
+
|
|
236
|
+
// Deploy a test token
|
|
237
|
+
let token = setup.deploy_test_token();
|
|
238
|
+
|
|
239
|
+
// Mint tokens to the treasury contract
|
|
240
|
+
let withdraw_amount = 1000_i128;
|
|
241
|
+
setup.mint_tokens(&token, &setup.treasury.address, withdraw_amount);
|
|
242
|
+
|
|
243
|
+
// Verify initial balance
|
|
244
|
+
let initial_balance = setup.get_token_balance(&token, &setup.treasury.address);
|
|
245
|
+
assert_eq!(initial_balance, withdraw_amount);
|
|
246
|
+
|
|
247
|
+
// Withdraw tokens as owner
|
|
248
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient, &withdraw_amount));
|
|
249
|
+
setup.treasury.withdraw_token(&token, &recipient, &withdraw_amount);
|
|
250
|
+
|
|
251
|
+
// Verify balances after withdrawal
|
|
252
|
+
let treasury_balance = setup.get_token_balance(&token, &setup.treasury.address);
|
|
253
|
+
let recipient_balance = setup.get_token_balance(&token, &recipient);
|
|
254
|
+
assert_eq!(treasury_balance, 0);
|
|
255
|
+
assert_eq!(recipient_balance, withdraw_amount);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#[test]
|
|
259
|
+
fn test_withdraw_token_partial_amount() {
|
|
260
|
+
let setup = setup();
|
|
261
|
+
|
|
262
|
+
let recipient = setup.create_contract_address();
|
|
263
|
+
let token = setup.deploy_test_token();
|
|
264
|
+
|
|
265
|
+
let initial_amount = 10000_i128;
|
|
266
|
+
let withdraw_amount = 3000_i128;
|
|
267
|
+
|
|
268
|
+
setup.mint_tokens(&token, &setup.treasury.address, initial_amount);
|
|
269
|
+
|
|
270
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient, &withdraw_amount));
|
|
271
|
+
setup.treasury.withdraw_token(&token, &recipient, &withdraw_amount);
|
|
272
|
+
|
|
273
|
+
// Verify partial withdrawal
|
|
274
|
+
let treasury_balance = setup.get_token_balance(&token, &setup.treasury.address);
|
|
275
|
+
let recipient_balance = setup.get_token_balance(&token, &recipient);
|
|
276
|
+
assert_eq!(treasury_balance, initial_amount - withdraw_amount);
|
|
277
|
+
assert_eq!(recipient_balance, withdraw_amount);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
#[test]
|
|
281
|
+
fn test_withdraw_token_invalid_amount_zero() {
|
|
282
|
+
let setup = setup();
|
|
283
|
+
|
|
284
|
+
let recipient = setup.create_contract_address();
|
|
285
|
+
let token = setup.deploy_test_token();
|
|
286
|
+
|
|
287
|
+
setup.mint_tokens(&token, &setup.treasury.address, 1000);
|
|
288
|
+
|
|
289
|
+
// With current implementation, withdrawing 0 is allowed (token contract permits it).
|
|
290
|
+
let treasury_balance_before = setup.get_token_balance(&token, &setup.treasury.address);
|
|
291
|
+
let recipient_balance_before = setup.get_token_balance(&token, &recipient);
|
|
292
|
+
|
|
293
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient, &0_i128));
|
|
294
|
+
let result = setup.treasury.try_withdraw_token(&token, &recipient, &0);
|
|
295
|
+
assert!(result.is_ok());
|
|
296
|
+
|
|
297
|
+
let treasury_balance_after = setup.get_token_balance(&token, &setup.treasury.address);
|
|
298
|
+
let recipient_balance_after = setup.get_token_balance(&token, &recipient);
|
|
299
|
+
assert_eq!(treasury_balance_after, treasury_balance_before);
|
|
300
|
+
assert_eq!(recipient_balance_after, recipient_balance_before);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
#[test]
|
|
304
|
+
fn test_withdraw_token_invalid_amount_negative() {
|
|
305
|
+
let setup = setup();
|
|
306
|
+
|
|
307
|
+
let recipient = setup.create_contract_address();
|
|
308
|
+
let token = setup.deploy_test_token();
|
|
309
|
+
|
|
310
|
+
setup.mint_tokens(&token, &setup.treasury.address, 1000);
|
|
311
|
+
|
|
312
|
+
// Try to withdraw negative amount
|
|
313
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient, &(-100_i128)));
|
|
314
|
+
let result = setup.treasury.try_withdraw_token(&token, &recipient, &-100);
|
|
315
|
+
assert!(result.is_err());
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
#[test]
|
|
319
|
+
fn test_withdraw_token_invalid_recipient() {
|
|
320
|
+
let setup = setup();
|
|
321
|
+
|
|
322
|
+
// Generate an address that doesn't exist as a contract (won't pass `.exists()`),
|
|
323
|
+
// but token transfers to such addresses are still allowed.
|
|
324
|
+
let non_existent_recipient = soroban_sdk::Address::generate(&setup.env);
|
|
325
|
+
let token = setup.deploy_test_token();
|
|
326
|
+
|
|
327
|
+
setup.mint_tokens(&token, &setup.treasury.address, 1000);
|
|
328
|
+
|
|
329
|
+
let treasury_balance_before = setup.get_token_balance(&token, &setup.treasury.address);
|
|
330
|
+
let recipient_balance_before = setup.get_token_balance(&token, &non_existent_recipient);
|
|
331
|
+
|
|
332
|
+
// Withdraw to a non-contract address (should succeed)
|
|
333
|
+
setup.mock_owner_auth("withdraw_token", (&token, &non_existent_recipient, &500_i128));
|
|
334
|
+
let result = setup.treasury.try_withdraw_token(&token, &non_existent_recipient, &500);
|
|
335
|
+
assert!(result.is_ok());
|
|
336
|
+
|
|
337
|
+
let treasury_balance_after = setup.get_token_balance(&token, &setup.treasury.address);
|
|
338
|
+
let recipient_balance_after = setup.get_token_balance(&token, &non_existent_recipient);
|
|
339
|
+
assert_eq!(treasury_balance_after, treasury_balance_before - 500);
|
|
340
|
+
assert_eq!(recipient_balance_after, recipient_balance_before + 500);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
#[test]
|
|
344
|
+
fn test_withdraw_token_insufficient_balance() {
|
|
345
|
+
let setup = setup();
|
|
346
|
+
|
|
347
|
+
let recipient = setup.create_contract_address();
|
|
348
|
+
let token = setup.deploy_test_token();
|
|
349
|
+
|
|
350
|
+
let balance = 500_i128;
|
|
351
|
+
let withdraw_amount = 1000_i128;
|
|
352
|
+
|
|
353
|
+
setup.mint_tokens(&token, &setup.treasury.address, balance);
|
|
354
|
+
|
|
355
|
+
// Try to withdraw more than balance
|
|
356
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient, &withdraw_amount));
|
|
357
|
+
let result = setup.treasury.try_withdraw_token(&token, &recipient, &withdraw_amount);
|
|
358
|
+
assert!(result.is_err());
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
#[test]
|
|
362
|
+
#[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
|
|
363
|
+
fn test_withdraw_token_not_owner() {
|
|
364
|
+
let setup = setup();
|
|
365
|
+
|
|
366
|
+
let non_owner = soroban_sdk::Address::generate(&setup.env);
|
|
367
|
+
let recipient = setup.create_contract_address();
|
|
368
|
+
let token = setup.deploy_test_token();
|
|
369
|
+
|
|
370
|
+
setup.mint_tokens(&token, &setup.treasury.address, 1000);
|
|
371
|
+
|
|
372
|
+
// Try to withdraw as non-owner
|
|
373
|
+
setup.mock_auth(&non_owner, "withdraw_token", (&token, &recipient, &500_i128));
|
|
374
|
+
setup.treasury.withdraw_token(&token, &recipient, &500);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
#[test]
|
|
378
|
+
fn test_withdraw_token_entire_balance() {
|
|
379
|
+
let setup = setup();
|
|
380
|
+
|
|
381
|
+
let recipient = setup.create_contract_address();
|
|
382
|
+
let token = setup.deploy_test_token();
|
|
383
|
+
|
|
384
|
+
let total_balance = 5000_i128;
|
|
385
|
+
setup.mint_tokens(&token, &setup.treasury.address, total_balance);
|
|
386
|
+
|
|
387
|
+
// Withdraw entire balance
|
|
388
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient, &total_balance));
|
|
389
|
+
setup.treasury.withdraw_token(&token, &recipient, &total_balance);
|
|
390
|
+
|
|
391
|
+
// Verify complete withdrawal
|
|
392
|
+
let treasury_balance = setup.get_token_balance(&token, &setup.treasury.address);
|
|
393
|
+
let recipient_balance = setup.get_token_balance(&token, &recipient);
|
|
394
|
+
assert_eq!(treasury_balance, 0);
|
|
395
|
+
assert_eq!(recipient_balance, total_balance);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
#[test]
|
|
399
|
+
fn test_withdraw_token_multiple_withdrawals() {
|
|
400
|
+
let setup = setup();
|
|
401
|
+
|
|
402
|
+
let recipient1 = setup.create_contract_address();
|
|
403
|
+
let recipient2 = setup.create_contract_address();
|
|
404
|
+
let token = setup.deploy_test_token();
|
|
405
|
+
|
|
406
|
+
let initial_balance = 10000_i128;
|
|
407
|
+
let first_withdrawal = 3000_i128;
|
|
408
|
+
let second_withdrawal = 2000_i128;
|
|
409
|
+
|
|
410
|
+
setup.mint_tokens(&token, &setup.treasury.address, initial_balance);
|
|
411
|
+
|
|
412
|
+
// First withdrawal
|
|
413
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient1, &first_withdrawal));
|
|
414
|
+
setup.treasury.withdraw_token(&token, &recipient1, &first_withdrawal);
|
|
415
|
+
|
|
416
|
+
// Second withdrawal to different recipient
|
|
417
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient2, &second_withdrawal));
|
|
418
|
+
setup.treasury.withdraw_token(&token, &recipient2, &second_withdrawal);
|
|
419
|
+
|
|
420
|
+
// Verify all balances
|
|
421
|
+
let treasury_balance = setup.get_token_balance(&token, &setup.treasury.address);
|
|
422
|
+
let recipient1_balance = setup.get_token_balance(&token, &recipient1);
|
|
423
|
+
let recipient2_balance = setup.get_token_balance(&token, &recipient2);
|
|
424
|
+
|
|
425
|
+
assert_eq!(treasury_balance, initial_balance - first_withdrawal - second_withdrawal);
|
|
426
|
+
assert_eq!(recipient1_balance, first_withdrawal);
|
|
427
|
+
assert_eq!(recipient2_balance, second_withdrawal);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
#[test]
|
|
431
|
+
fn test_withdraw_token_multiple_tokens() {
|
|
432
|
+
let setup = setup();
|
|
433
|
+
|
|
434
|
+
let recipient = setup.create_contract_address();
|
|
435
|
+
let token1 = setup.deploy_test_token();
|
|
436
|
+
let token2 = setup.deploy_test_token();
|
|
437
|
+
|
|
438
|
+
let amount1 = 1000_i128;
|
|
439
|
+
let amount2 = 2000_i128;
|
|
440
|
+
|
|
441
|
+
// Setup balances for two different tokens
|
|
442
|
+
setup.mint_tokens(&token1, &setup.treasury.address, amount1);
|
|
443
|
+
setup.mint_tokens(&token2, &setup.treasury.address, amount2);
|
|
444
|
+
|
|
445
|
+
// Withdraw from first token
|
|
446
|
+
setup.mock_owner_auth("withdraw_token", (&token1, &recipient, &amount1));
|
|
447
|
+
setup.treasury.withdraw_token(&token1, &recipient, &amount1);
|
|
448
|
+
|
|
449
|
+
// Withdraw from second token
|
|
450
|
+
setup.mock_owner_auth("withdraw_token", (&token2, &recipient, &amount2));
|
|
451
|
+
setup.treasury.withdraw_token(&token2, &recipient, &amount2);
|
|
452
|
+
|
|
453
|
+
// Verify balances for both tokens
|
|
454
|
+
assert_eq!(setup.get_token_balance(&token1, &setup.treasury.address), 0);
|
|
455
|
+
assert_eq!(setup.get_token_balance(&token2, &setup.treasury.address), 0);
|
|
456
|
+
assert_eq!(setup.get_token_balance(&token1, &recipient), amount1);
|
|
457
|
+
assert_eq!(setup.get_token_balance(&token2, &recipient), amount2);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
#[test]
|
|
461
|
+
fn test_withdraw_token_events_emitted() {
|
|
462
|
+
let setup = setup();
|
|
463
|
+
|
|
464
|
+
let recipient = setup.create_contract_address();
|
|
465
|
+
let token = setup.deploy_test_token();
|
|
466
|
+
let amount = 500_i128;
|
|
467
|
+
|
|
468
|
+
setup.mint_tokens(&token, &setup.treasury.address, amount);
|
|
469
|
+
|
|
470
|
+
// Count events before withdrawal
|
|
471
|
+
let events_before = setup.env.events().all().len();
|
|
472
|
+
|
|
473
|
+
// Withdraw tokens and check that events are emitted
|
|
474
|
+
setup.mock_owner_auth("withdraw_token", (&token, &recipient, &amount));
|
|
475
|
+
setup.treasury.withdraw_token(&token, &recipient, &amount);
|
|
476
|
+
|
|
477
|
+
// Verify that new events were published
|
|
478
|
+
let events_after = setup.env.events().all().len();
|
|
479
|
+
assert!(events_after > events_before, "TokenWithdrawn event should be emitted");
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// ============================================================================
|
|
483
|
+
// Integration Tests
|
|
484
|
+
// ============================================================================
|
|
485
|
+
|
|
486
|
+
#[test]
|
|
487
|
+
fn test_complete_workflow() {
|
|
488
|
+
let setup = setup();
|
|
489
|
+
|
|
490
|
+
let sender = soroban_sdk::Address::generate(&setup.env);
|
|
491
|
+
let dst_eid = 101_u32;
|
|
492
|
+
|
|
493
|
+
// === STEP 1: Initial Configuration ===
|
|
494
|
+
setup.configure_treasury(250);
|
|
495
|
+
|
|
496
|
+
// === STEP 2: Test Native Fee Calculation ===
|
|
497
|
+
let total_worker_fee: i128 = 10000;
|
|
498
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &total_worker_fee, &false);
|
|
499
|
+
assert_eq!(fee, 250); // 10000 * 250 / 10000 = 250
|
|
500
|
+
|
|
501
|
+
// === STEP 3: Test Fee Disable ===
|
|
502
|
+
setup.mock_owner_auth("set_fee_enabled", (&false,));
|
|
503
|
+
setup.treasury.set_fee_enabled(&false);
|
|
504
|
+
let fee = setup.treasury.get_fee(&sender, &dst_eid, &total_worker_fee, &false);
|
|
505
|
+
assert_eq!(fee, 0); // Should return 0 when disabled
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// ============================================================================
|
|
509
|
+
// View Function Tests
|
|
510
|
+
// ============================================================================
|
|
511
|
+
|
|
512
|
+
#[test]
|
|
513
|
+
fn test_view_functions_consistency() {
|
|
514
|
+
let setup = setup();
|
|
515
|
+
|
|
516
|
+
let native_fee_bp: u32 = 750; // 7.5%
|
|
517
|
+
|
|
518
|
+
setup.configure_treasury(native_fee_bp);
|
|
519
|
+
|
|
520
|
+
// Verify all view functions return correct values
|
|
521
|
+
assert_eq!(setup.treasury.native_fee_bp(), native_fee_bp);
|
|
522
|
+
assert!(setup.treasury.fee_enabled());
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// ============================================================================
|
|
526
|
+
// Authorization Tests
|
|
527
|
+
// ============================================================================
|
|
528
|
+
|
|
529
|
+
#[test]
|
|
530
|
+
#[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
|
|
531
|
+
fn test_set_native_fee_bp_not_owner() {
|
|
532
|
+
let setup = setup();
|
|
533
|
+
|
|
534
|
+
let non_owner = soroban_sdk::Address::generate(&setup.env);
|
|
535
|
+
|
|
536
|
+
setup.mock_auth(&non_owner, "set_native_fee_bp", (&500_u32,));
|
|
537
|
+
setup.treasury.set_native_fee_bp(&500);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
#[test]
|
|
541
|
+
#[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
|
|
542
|
+
fn test_set_fee_enabled_not_owner() {
|
|
543
|
+
let setup = setup();
|
|
544
|
+
|
|
545
|
+
let non_owner = soroban_sdk::Address::generate(&setup.env);
|
|
546
|
+
|
|
547
|
+
setup.mock_auth(&non_owner, "set_fee_enabled", (&true,));
|
|
548
|
+
setup.treasury.set_fee_enabled(&true);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
#[test]
|
|
552
|
+
#[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
|
|
553
|
+
fn test_set_zro_fee_lib_not_owner() {
|
|
554
|
+
let setup = setup();
|
|
555
|
+
|
|
556
|
+
let non_owner = soroban_sdk::Address::generate(&setup.env);
|
|
557
|
+
// Use contract address since it needs to pass .exists() check
|
|
558
|
+
let fee_lib = setup.create_contract_address();
|
|
559
|
+
|
|
560
|
+
setup.mock_auth(&non_owner, "set_zro_fee_lib", (&Some(fee_lib.clone()),));
|
|
561
|
+
setup.treasury.set_zro_fee_lib(&Some(fee_lib));
|
|
562
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
errors::TreasuryError,
|
|
3
|
+
events::{FeeEnabledSet, NativeFeeBpSet, TokenWithdrawn, ZROFeeLibSet},
|
|
4
|
+
interfaces::ZROFeeLibClient,
|
|
5
|
+
storage::TreasuryStorage,
|
|
6
|
+
};
|
|
7
|
+
use common_macros::{only_owner, ttl_configurable};
|
|
8
|
+
use message_lib_common::ILayerZeroTreasury;
|
|
9
|
+
use soroban_sdk::{assert_with_error, contract, contractimpl, token::Client, Address, Env, Executable};
|
|
10
|
+
use utils::option_ext::OptionExt;
|
|
11
|
+
|
|
12
|
+
/// Denominator for basis point calculations (10000 = 100%).
|
|
13
|
+
const BPS_DENOMINATOR: u32 = 10000;
|
|
14
|
+
|
|
15
|
+
#[contract]
|
|
16
|
+
#[ttl_configurable]
|
|
17
|
+
pub struct Treasury;
|
|
18
|
+
|
|
19
|
+
#[contractimpl]
|
|
20
|
+
impl Treasury {
|
|
21
|
+
pub fn __constructor(env: &Env, owner: &Address) {
|
|
22
|
+
Self::__init_owner(env, owner);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ===== Admin Functions =====
|
|
26
|
+
|
|
27
|
+
/// Sets the native fee percentage in basis points.
|
|
28
|
+
///
|
|
29
|
+
/// # Arguments
|
|
30
|
+
/// * `native_fee_bp` - Fee percentage in basis points (0-10000, where 10000 = 100%)
|
|
31
|
+
#[only_owner]
|
|
32
|
+
pub fn set_native_fee_bp(env: &Env, native_fee_bp: u32) {
|
|
33
|
+
assert_with_error!(env, native_fee_bp <= BPS_DENOMINATOR, TreasuryError::InvalidNativeFeeBp);
|
|
34
|
+
TreasuryStorage::set_native_fee_bp(env, &native_fee_bp);
|
|
35
|
+
NativeFeeBpSet { native_fee_bp }.publish(env);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Enables or disables fee collection globally.
|
|
39
|
+
///
|
|
40
|
+
/// # Arguments
|
|
41
|
+
/// * `fee_enabled` - Whether fee collection is enabled
|
|
42
|
+
#[only_owner]
|
|
43
|
+
pub fn set_fee_enabled(env: &Env, fee_enabled: bool) {
|
|
44
|
+
TreasuryStorage::set_fee_enabled(env, &fee_enabled);
|
|
45
|
+
FeeEnabledSet { fee_enabled }.publish(env);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// Sets or removes the ZRO fee library for custom ZRO token fee calculations.
|
|
49
|
+
///
|
|
50
|
+
/// # Arguments
|
|
51
|
+
/// * `zro_fee_lib` - The ZRO fee library contract address, or `None` to remove
|
|
52
|
+
#[only_owner]
|
|
53
|
+
pub fn set_zro_fee_lib(env: &Env, zro_fee_lib: &Option<Address>) {
|
|
54
|
+
if let Some(ref lib) = zro_fee_lib {
|
|
55
|
+
assert_with_error!(
|
|
56
|
+
env,
|
|
57
|
+
matches!(lib.executable(), Some(Executable::Wasm(_))),
|
|
58
|
+
TreasuryError::InvalidZROFeeLib
|
|
59
|
+
);
|
|
60
|
+
TreasuryStorage::set_zro_fee_lib(env, lib);
|
|
61
|
+
} else {
|
|
62
|
+
TreasuryStorage::remove_zro_fee_lib(env);
|
|
63
|
+
}
|
|
64
|
+
ZROFeeLibSet { zro_fee_lib: zro_fee_lib.clone() }.publish(env);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// Withdraws any token (including native XLM) from the contract to a specified address.
|
|
68
|
+
///
|
|
69
|
+
/// Only the contract owner can execute this method.
|
|
70
|
+
///
|
|
71
|
+
/// # Arguments
|
|
72
|
+
/// * `token` - The token contract address (can be native XLM or any other token)
|
|
73
|
+
/// * `to` - The recipient address
|
|
74
|
+
/// * `amount` - The amount to withdraw (must be positive)
|
|
75
|
+
#[only_owner]
|
|
76
|
+
pub fn withdraw_token(env: &Env, token: &Address, to: &Address, amount: i128) {
|
|
77
|
+
let token_client = Client::new(env, token);
|
|
78
|
+
token_client.transfer(&env.current_contract_address(), to, &amount);
|
|
79
|
+
|
|
80
|
+
TokenWithdrawn { token: token.clone(), to: to.clone(), amount }.publish(env);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ===== View Functions =====
|
|
84
|
+
|
|
85
|
+
/// Returns the native fee percentage in basis points.
|
|
86
|
+
pub fn native_fee_bp(env: &Env) -> u32 {
|
|
87
|
+
TreasuryStorage::native_fee_bp(env).unwrap_or(0)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// Returns whether fee collection is enabled.
|
|
91
|
+
pub fn fee_enabled(env: &Env) -> bool {
|
|
92
|
+
TreasuryStorage::fee_enabled(env).unwrap_or(false)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/// Returns the ZRO fee library address if set.
|
|
96
|
+
pub fn zro_fee_lib(env: &Env) -> Option<Address> {
|
|
97
|
+
TreasuryStorage::zro_fee_lib(env)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ===== Internal Functions =====
|
|
101
|
+
|
|
102
|
+
/// Calculates the treasury fee based on the total native fee and configured basis points.
|
|
103
|
+
fn calculate_native_fee(env: &Env, total_native_fee: i128) -> i128 {
|
|
104
|
+
total_native_fee * Self::native_fee_bp(env) as i128 / BPS_DENOMINATOR as i128
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/// Returns the ZRO fee library client, panics if not set.
|
|
108
|
+
fn get_zro_fee_lib_client(env: &Env) -> ZROFeeLibClient<'static> {
|
|
109
|
+
let fee_lib = Self::zro_fee_lib(env).unwrap_or_panic(env, TreasuryError::ZROFeeLibNotSet);
|
|
110
|
+
ZROFeeLibClient::new(env, &fee_lib)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// ILayerZeroTreasury Implementation
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
#[contractimpl]
|
|
119
|
+
impl ILayerZeroTreasury for Treasury {
|
|
120
|
+
/// Get the treasury fee for a cross-chain message.
|
|
121
|
+
///
|
|
122
|
+
/// Returns 0 if fee collection is disabled. For ZRO payments, delegates to the ZRO fee library.
|
|
123
|
+
fn get_fee(env: &Env, sender: &Address, dst_eid: u32, total_native_fee: i128, pay_in_zro: bool) -> i128 {
|
|
124
|
+
assert_with_error!(env, total_native_fee >= 0, TreasuryError::InvalidTotalNativeFee);
|
|
125
|
+
|
|
126
|
+
if !Self::fee_enabled(env) {
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let native_treasury_fee = Self::calculate_native_fee(env, total_native_fee);
|
|
131
|
+
if pay_in_zro {
|
|
132
|
+
let zro_fee =
|
|
133
|
+
Self::get_zro_fee_lib_client(env).get_fee(sender, &dst_eid, &total_native_fee, &native_treasury_fee);
|
|
134
|
+
assert_with_error!(env, zro_fee >= 0, TreasuryError::InvalidZROFee);
|
|
135
|
+
zro_fee
|
|
136
|
+
} else {
|
|
137
|
+
native_treasury_fee
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|