@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,283 @@
|
|
|
1
|
+
use crate as oapp;
|
|
2
|
+
use crate::{errors::OAppError, oapp_core::OAppCore};
|
|
3
|
+
use endpoint_v2::{MessagingFee, MessagingParams, MessagingReceipt};
|
|
4
|
+
use soroban_sdk::{
|
|
5
|
+
contract, contractimpl, symbol_short,
|
|
6
|
+
testutils::{Address as _, MockAuth, MockAuthInvoke},
|
|
7
|
+
token::{StellarAssetClient, TokenClient},
|
|
8
|
+
Address, Bytes, BytesN, Env, IntoVal,
|
|
9
|
+
};
|
|
10
|
+
use utils::ownable::Ownable;
|
|
11
|
+
|
|
12
|
+
// Mock Endpoint contract
|
|
13
|
+
#[contract]
|
|
14
|
+
pub struct MockEndpoint;
|
|
15
|
+
|
|
16
|
+
#[contractimpl]
|
|
17
|
+
impl MockEndpoint {
|
|
18
|
+
pub fn __constructor(env: Env, zro_token: &Address, native_token: &Address) {
|
|
19
|
+
env.storage().instance().set(&symbol_short!("zro"), zro_token);
|
|
20
|
+
env.storage().instance().set(&symbol_short!("ntk"), native_token);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub fn set_delegate(_env: Env, _oapp: Address, _delegate: Option<Address>) {
|
|
24
|
+
// do nothing in mock
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn quote(_env: Env, _sender: Address, params: MessagingParams) -> MessagingFee {
|
|
28
|
+
MessagingFee { native_fee: 1000, zro_fee: if params.pay_in_zro { 500 } else { 0 } }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub fn send(env: Env, _sender: Address, params: MessagingParams, _refund_address: Address) -> MessagingReceipt {
|
|
32
|
+
// Return mock receipt
|
|
33
|
+
MessagingReceipt {
|
|
34
|
+
guid: BytesN::from_array(&env, &[1u8; 32]),
|
|
35
|
+
nonce: 1,
|
|
36
|
+
fee: MessagingFee { native_fee: 1000, zro_fee: if params.pay_in_zro { 500 } else { 0 } },
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub fn zro(env: Env) -> Option<Address> {
|
|
41
|
+
// Return a mock ZRO token address
|
|
42
|
+
env.storage().instance().get(&symbol_short!("zro")).unwrap()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub fn native_token(env: Env) -> Address {
|
|
46
|
+
env.storage().instance().get(&symbol_short!("ntk")).unwrap()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[oapp_macros::oapp_sender]
|
|
51
|
+
pub struct DummyOAppSender;
|
|
52
|
+
|
|
53
|
+
#[contractimpl]
|
|
54
|
+
impl DummyOAppSender {
|
|
55
|
+
pub fn __constructor(env: &Env, owner: &Address, endpoint: &Address) {
|
|
56
|
+
Self::__init_owner(env, owner);
|
|
57
|
+
Self::__oapp_initialize(env, endpoint, &None);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pub fn quote(env: &Env, dst_eid: u32, message: &Bytes, options: &Bytes, pay_in_zro: bool) -> MessagingFee {
|
|
61
|
+
Self::__quote(env, dst_eid, message, options, pay_in_zro)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
pub fn lz_send(
|
|
65
|
+
env: &Env,
|
|
66
|
+
sender: &Address,
|
|
67
|
+
dst_eid: u32,
|
|
68
|
+
message: &Bytes,
|
|
69
|
+
options: &Bytes,
|
|
70
|
+
fee: &MessagingFee,
|
|
71
|
+
refund_address: &Address,
|
|
72
|
+
) -> MessagingReceipt {
|
|
73
|
+
sender.require_auth();
|
|
74
|
+
Self::__lz_send(env, sender, dst_eid, message, options, fee, refund_address)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
pub fn pay_native(env: &Env, payer: &Address, native_fee: i128) {
|
|
78
|
+
payer.require_auth();
|
|
79
|
+
Self::__pay_native(env, payer, native_fee)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
pub fn pay_zro(env: &Env, payer: &Address, zro_fee: i128) {
|
|
83
|
+
payer.require_auth();
|
|
84
|
+
Self::__pay_zro(env, payer, zro_fee)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const REMOTE_EID: u32 = 100;
|
|
89
|
+
const UNSET_EID: u32 = 999;
|
|
90
|
+
|
|
91
|
+
struct TestSetup<'a> {
|
|
92
|
+
env: Env,
|
|
93
|
+
#[allow(dead_code)]
|
|
94
|
+
token_admin: Address,
|
|
95
|
+
endpoint: Address,
|
|
96
|
+
#[allow(dead_code)]
|
|
97
|
+
owner: Address,
|
|
98
|
+
oapp_client: DummyOAppSenderClient<'a>,
|
|
99
|
+
native_token_client: TokenClient<'a>,
|
|
100
|
+
native_token_admin_client: StellarAssetClient<'a>,
|
|
101
|
+
zro_token_admin_client: StellarAssetClient<'a>,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fn setup<'a>() -> TestSetup<'a> {
|
|
105
|
+
let env = Env::default();
|
|
106
|
+
|
|
107
|
+
let owner = Address::generate(&env);
|
|
108
|
+
|
|
109
|
+
let token_admin = Address::generate(&env);
|
|
110
|
+
// Deploy mock tokens
|
|
111
|
+
let native_token_sac = env.register_stellar_asset_contract_v2(token_admin.clone());
|
|
112
|
+
let native_token = native_token_sac.address();
|
|
113
|
+
let native_token_client = TokenClient::new(&env, &native_token);
|
|
114
|
+
let native_token_admin_client = StellarAssetClient::new(&env, &native_token);
|
|
115
|
+
|
|
116
|
+
let zro_token_sac = env.register_stellar_asset_contract_v2(token_admin.clone());
|
|
117
|
+
let zro_token = zro_token_sac.address();
|
|
118
|
+
let zro_token_admin_client = StellarAssetClient::new(&env, &zro_token);
|
|
119
|
+
|
|
120
|
+
// Deploy mock endpoint
|
|
121
|
+
let endpoint = env.register(MockEndpoint, (&zro_token, &native_token));
|
|
122
|
+
|
|
123
|
+
// Deploy OApp
|
|
124
|
+
let oapp = env.register(DummyOAppSender, (&owner, &endpoint));
|
|
125
|
+
let oapp_client = DummyOAppSenderClient::new(&env, &oapp);
|
|
126
|
+
|
|
127
|
+
TestSetup {
|
|
128
|
+
env,
|
|
129
|
+
endpoint,
|
|
130
|
+
token_admin,
|
|
131
|
+
native_token_client,
|
|
132
|
+
native_token_admin_client,
|
|
133
|
+
zro_token_admin_client,
|
|
134
|
+
owner,
|
|
135
|
+
oapp_client,
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
#[test]
|
|
140
|
+
fn test_quote_with_peer_set() {
|
|
141
|
+
let TestSetup { env, owner, oapp_client, .. } = setup();
|
|
142
|
+
|
|
143
|
+
// Set peer for destination
|
|
144
|
+
let peer = BytesN::from_array(&env, &[1; 32]);
|
|
145
|
+
let peer_option = Some(peer.clone());
|
|
146
|
+
env.mock_auths(&[MockAuth {
|
|
147
|
+
address: &owner,
|
|
148
|
+
invoke: &MockAuthInvoke {
|
|
149
|
+
contract: &oapp_client.address,
|
|
150
|
+
fn_name: "set_peer",
|
|
151
|
+
args: (&REMOTE_EID, &peer_option).into_val(&env),
|
|
152
|
+
sub_invokes: &[],
|
|
153
|
+
},
|
|
154
|
+
}]);
|
|
155
|
+
oapp_client.set_peer(&REMOTE_EID, &peer_option);
|
|
156
|
+
|
|
157
|
+
let message = Bytes::from_array(&env, &[1, 2, 3, 4, 5]);
|
|
158
|
+
let options = Bytes::from_array(&env, &[6, 7, 8]);
|
|
159
|
+
|
|
160
|
+
// Test quote without ZRO
|
|
161
|
+
let fee = oapp_client.quote(&REMOTE_EID, &message, &options, &false);
|
|
162
|
+
assert!(fee.native_fee > 0);
|
|
163
|
+
assert_eq!(fee.zro_fee, 0);
|
|
164
|
+
|
|
165
|
+
// Test quote with ZRO
|
|
166
|
+
let fee_with_zro = oapp_client.quote(&REMOTE_EID, &message, &options, &true);
|
|
167
|
+
assert!(fee_with_zro.native_fee > 0);
|
|
168
|
+
assert!(fee_with_zro.zro_fee > 0);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#[test]
|
|
172
|
+
fn test_quote_without_peer_panics() {
|
|
173
|
+
let TestSetup { env, oapp_client, .. } = setup();
|
|
174
|
+
|
|
175
|
+
let message = Bytes::from_array(&env, &[1, 2, 3]);
|
|
176
|
+
let options = Bytes::from_array(&env, &[]);
|
|
177
|
+
|
|
178
|
+
// This should panic because no peer is set for UNSET_EID
|
|
179
|
+
let result = oapp_client.try_quote(&UNSET_EID, &message, &options, &false);
|
|
180
|
+
assert_eq!(result.err().unwrap().ok().unwrap(), OAppError::NoPeer.into());
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
#[test]
|
|
184
|
+
fn test_lz_send_native_only() {
|
|
185
|
+
let TestSetup { env, oapp_client, endpoint, native_token_client, native_token_admin_client, .. } = setup();
|
|
186
|
+
|
|
187
|
+
env.mock_all_auths();
|
|
188
|
+
|
|
189
|
+
// Setup peer
|
|
190
|
+
let peer = BytesN::from_array(&env, &[2; 32]);
|
|
191
|
+
oapp_client.set_peer(&REMOTE_EID, &Some(peer));
|
|
192
|
+
|
|
193
|
+
// Setup sender with funds
|
|
194
|
+
let sender = Address::generate(&env);
|
|
195
|
+
let initial_balance = 10000i128;
|
|
196
|
+
native_token_admin_client.mint(&sender, &initial_balance);
|
|
197
|
+
|
|
198
|
+
let message = Bytes::from_array(&env, &[1, 2, 3]);
|
|
199
|
+
let options = Bytes::from_array(&env, &[]);
|
|
200
|
+
let refund_address = Address::generate(&env);
|
|
201
|
+
|
|
202
|
+
let fee = MessagingFee { native_fee: 1000, zro_fee: 0 };
|
|
203
|
+
|
|
204
|
+
// Send message (auth is mocked automatically)
|
|
205
|
+
let receipt = oapp_client.lz_send(&sender, &REMOTE_EID, &message, &options, &fee, &refund_address);
|
|
206
|
+
|
|
207
|
+
// Verify receipt
|
|
208
|
+
assert_eq!(receipt.nonce, 1);
|
|
209
|
+
assert_eq!(receipt.fee.native_fee, fee.native_fee);
|
|
210
|
+
|
|
211
|
+
// Verify native token was transferred to endpoint
|
|
212
|
+
let sender_balance = native_token_client.balance(&sender);
|
|
213
|
+
assert_eq!(sender_balance, initial_balance - fee.native_fee);
|
|
214
|
+
|
|
215
|
+
let endpoint_balance = native_token_client.balance(&endpoint);
|
|
216
|
+
assert_eq!(endpoint_balance, fee.native_fee);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
#[test]
|
|
220
|
+
fn test_lz_send_with_zro() {
|
|
221
|
+
let TestSetup { env, oapp_client, native_token_admin_client, zro_token_admin_client, .. } = setup();
|
|
222
|
+
|
|
223
|
+
env.mock_all_auths();
|
|
224
|
+
|
|
225
|
+
// Setup peer
|
|
226
|
+
let peer = BytesN::from_array(&env, &[3; 32]);
|
|
227
|
+
oapp_client.set_peer(&REMOTE_EID, &Some(peer));
|
|
228
|
+
|
|
229
|
+
// Setup sender with both native and ZRO funds
|
|
230
|
+
let fee = MessagingFee { native_fee: 1000, zro_fee: 500 };
|
|
231
|
+
|
|
232
|
+
let sender = Address::generate(&env);
|
|
233
|
+
native_token_admin_client.mint(&sender, &fee.native_fee);
|
|
234
|
+
zro_token_admin_client.mint(&sender, &fee.zro_fee);
|
|
235
|
+
|
|
236
|
+
let message = Bytes::from_array(&env, &[1, 2, 3, 4]);
|
|
237
|
+
let options = Bytes::from_array(&env, &[5]);
|
|
238
|
+
let refund_address = Address::generate(&env);
|
|
239
|
+
|
|
240
|
+
// Send message with ZRO payment
|
|
241
|
+
let receipt = oapp_client.lz_send(&sender, &REMOTE_EID, &message, &options, &fee, &refund_address);
|
|
242
|
+
|
|
243
|
+
assert_eq!(receipt.fee.zro_fee, fee.zro_fee);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
#[test]
|
|
247
|
+
fn test_pay_native() {
|
|
248
|
+
let TestSetup { env, oapp_client, endpoint, native_token_admin_client, .. } = setup();
|
|
249
|
+
|
|
250
|
+
env.mock_all_auths();
|
|
251
|
+
|
|
252
|
+
let payer = Address::generate(&env);
|
|
253
|
+
let payment_amount = 2000i128;
|
|
254
|
+
|
|
255
|
+
// Fund the payer
|
|
256
|
+
native_token_admin_client.mint(&payer, &payment_amount);
|
|
257
|
+
|
|
258
|
+
// Make payment
|
|
259
|
+
oapp_client.pay_native(&payer, &payment_amount);
|
|
260
|
+
|
|
261
|
+
// Verify balances
|
|
262
|
+
assert_eq!(native_token_admin_client.balance(&payer), 0);
|
|
263
|
+
assert_eq!(native_token_admin_client.balance(&endpoint), payment_amount);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
#[test]
|
|
267
|
+
#[should_panic(expected = "balance is not sufficient to spend")]
|
|
268
|
+
fn test_pay_native_insufficient_balance() {
|
|
269
|
+
let TestSetup { env, oapp_client, native_token_admin_client, .. } = setup();
|
|
270
|
+
|
|
271
|
+
env.mock_all_auths();
|
|
272
|
+
|
|
273
|
+
let balance = 500i128;
|
|
274
|
+
let payment_amount = 1000i128;
|
|
275
|
+
|
|
276
|
+
let payer = Address::generate(&env);
|
|
277
|
+
|
|
278
|
+
// Fund with less than required
|
|
279
|
+
native_token_admin_client.mint(&payer, &balance);
|
|
280
|
+
|
|
281
|
+
// This should panic due to insufficient balance
|
|
282
|
+
oapp_client.pay_native(&payer, &payment_amount);
|
|
283
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "utils"
|
|
3
|
+
version.workspace = true
|
|
4
|
+
edition.workspace = true
|
|
5
|
+
license.workspace = true
|
|
6
|
+
publish = false
|
|
7
|
+
|
|
8
|
+
[lib]
|
|
9
|
+
crate-type = ["rlib"]
|
|
10
|
+
doctest = false
|
|
11
|
+
|
|
12
|
+
[features]
|
|
13
|
+
testutils = []
|
|
14
|
+
|
|
15
|
+
[dependencies]
|
|
16
|
+
soroban-sdk = { workspace = true }
|
|
17
|
+
common-macros = { workspace = true }
|
|
18
|
+
|
|
19
|
+
[dev-dependencies]
|
|
20
|
+
soroban-sdk = { workspace = true, features = ["testutils"] }
|
|
21
|
+
stellar-strkey = "0.0.14"
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
use soroban_sdk::{
|
|
2
|
+
address_payload::AddressPayload, assert_with_error, panic_with_error, Address, Bytes, BytesN, Env, U256,
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
use crate::{
|
|
6
|
+
buffer_writer::{ACCOUNT_PAYLOAD_TYPE, CONTRACT_PAYLOAD_TYPE},
|
|
7
|
+
bytes_ext::BytesExt,
|
|
8
|
+
errors::BufferReaderError,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/// Macro to generate read methods for primitive integer types (big-endian).
|
|
12
|
+
macro_rules! impl_read_uint {
|
|
13
|
+
($($method:ident, $type:ty, $len:expr);* $(;)?) => {
|
|
14
|
+
$(
|
|
15
|
+
pub fn $method(&mut self) -> $type {
|
|
16
|
+
<$type>::from_be_bytes(self.read_bytes($len).to_array())
|
|
17
|
+
}
|
|
18
|
+
)*
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/// A sequential reader for parsing binary data from a byte buffer.
|
|
23
|
+
///
|
|
24
|
+
/// Maintains a position cursor that advances as data is read.
|
|
25
|
+
/// All integer reads are big-endian.
|
|
26
|
+
pub struct BufferReader<'a> {
|
|
27
|
+
buffer: &'a Bytes,
|
|
28
|
+
pos: u32,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
impl<'a> BufferReader<'a> {
|
|
32
|
+
/// Creates a new reader starting at position 0.
|
|
33
|
+
pub fn new(buffer: &'a Bytes) -> Self {
|
|
34
|
+
Self { buffer, pos: 0 }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// TODO: should we pass and return a self instead of mutable reference?
|
|
38
|
+
/// Sets the absolute position in the buffer.
|
|
39
|
+
pub fn set_position(&mut self, pos: u32) -> &mut Self {
|
|
40
|
+
assert_with_error!(self.buffer.env(), pos <= self.buffer.len(), BufferReaderError::InvalidLength);
|
|
41
|
+
self.pos = pos;
|
|
42
|
+
self
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// Advances the position by `len` bytes without reading.
|
|
46
|
+
pub fn skip(&mut self, len: u32) -> &mut Self {
|
|
47
|
+
self.set_position(self.pos + len)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Moves the position backwards by `len` bytes.
|
|
51
|
+
pub fn rewind(&mut self, len: u32) -> &mut Self {
|
|
52
|
+
assert_with_error!(self.buffer.env(), self.pos >= len, BufferReaderError::InvalidLength);
|
|
53
|
+
self.pos -= len;
|
|
54
|
+
self
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Generates: read_u8 (1 byte), read_u16 (2 bytes), read_u32 (4 bytes), read_u64 (8 bytes), read_u128 (16 bytes)
|
|
58
|
+
impl_read_uint!(read_u8, u8, 1; read_u16, u16, 2; read_u32, u32, 4; read_u64, u64, 8; read_u128, u128, 16);
|
|
59
|
+
|
|
60
|
+
/// Reads a boolean (1 byte, non-zero = true).
|
|
61
|
+
pub fn read_bool(&mut self) -> bool {
|
|
62
|
+
self.read_u8() != 0
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Reads a U256 (32 bytes, big-endian).
|
|
66
|
+
pub fn read_u256(&mut self) -> U256 {
|
|
67
|
+
U256::from_be_bytes(self.buffer.env(), &self.read_bytes(32))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// Reads a Stellar address (33 bytes: 1 type + 32 payload).
|
|
71
|
+
pub fn read_address(&mut self) -> Address {
|
|
72
|
+
let payload_type = self.read_u8();
|
|
73
|
+
let payload = self.read_address_payload();
|
|
74
|
+
self.compose_address(payload_type, payload)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/// Reads an address payload only from the buffer (32 bytes).
|
|
78
|
+
pub fn read_address_payload(&mut self) -> BytesN<32> {
|
|
79
|
+
self.read_bytes_n()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// Reads N bytes as a fixed-size BytesN<N>.
|
|
83
|
+
pub fn read_bytes_n<const N: usize>(&mut self) -> BytesN<N> {
|
|
84
|
+
BytesN::<N>::from_array(self.buffer.env(), &self.read_bytes(N as u32).to_array())
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Reads `len` bytes from current position and advances.
|
|
88
|
+
pub fn read_bytes(&mut self, len: u32) -> Bytes {
|
|
89
|
+
let end = self.pos + len;
|
|
90
|
+
assert_with_error!(self.buffer.env(), self.buffer.len() >= end, BufferReaderError::InvalidLength);
|
|
91
|
+
|
|
92
|
+
let value = self.buffer.slice(self.pos..end);
|
|
93
|
+
self.pos = end;
|
|
94
|
+
value
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/// Reads all remaining bytes from current position to end.
|
|
98
|
+
pub fn read_bytes_until_end(&mut self) -> Bytes {
|
|
99
|
+
self.read_bytes(self.remaining())
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// Returns the current read position.
|
|
103
|
+
pub fn position(&self) -> u32 {
|
|
104
|
+
self.pos
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/// Returns a reference to the underlying buffer.
|
|
108
|
+
pub fn buffer(&self) -> &Bytes {
|
|
109
|
+
self.buffer
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/// Returns the total length of the buffer.
|
|
113
|
+
pub fn len(&self) -> u32 {
|
|
114
|
+
self.buffer.len()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Returns true if the buffer is empty.
|
|
118
|
+
pub fn is_empty(&self) -> bool {
|
|
119
|
+
self.buffer.is_empty()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// Returns the number of bytes remaining after current position.
|
|
123
|
+
pub fn remaining(&self) -> u32 {
|
|
124
|
+
self.buffer.len() - self.pos
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// Returns the Soroban environment reference.
|
|
128
|
+
pub fn env(&self) -> &Env {
|
|
129
|
+
self.buffer.env()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// === Internal Functions ===
|
|
133
|
+
|
|
134
|
+
/// Compose an address from its type byte and 32-byte payload.
|
|
135
|
+
fn compose_address(&self, payload_type: u8, payload: BytesN<32>) -> Address {
|
|
136
|
+
let addr_payload = match payload_type {
|
|
137
|
+
ACCOUNT_PAYLOAD_TYPE => AddressPayload::AccountIdPublicKeyEd25519(payload),
|
|
138
|
+
CONTRACT_PAYLOAD_TYPE => AddressPayload::ContractIdHash(payload),
|
|
139
|
+
_ => panic_with_error!(self.buffer.env(), BufferReaderError::InvalidAddressPayload),
|
|
140
|
+
};
|
|
141
|
+
Address::from_payload(self.buffer.env(), addr_payload)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
use soroban_sdk::{address_payload::AddressPayload, Address, Bytes, BytesN, Env, U256};
|
|
2
|
+
|
|
3
|
+
use crate::{errors::BufferWriterError, option_ext::OptionExt};
|
|
4
|
+
|
|
5
|
+
/// Macro to generate write methods for primitive integer types (big-endian).
|
|
6
|
+
macro_rules! impl_write_uint {
|
|
7
|
+
($($method:ident, $type:ty);* $(;)?) => {
|
|
8
|
+
$(
|
|
9
|
+
pub fn $method(&mut self, value: $type) -> &mut Self {
|
|
10
|
+
self.buffer.extend_from_slice(&value.to_be_bytes());
|
|
11
|
+
self
|
|
12
|
+
}
|
|
13
|
+
)*
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
pub const ACCOUNT_PAYLOAD_TYPE: u8 = 0;
|
|
18
|
+
pub const CONTRACT_PAYLOAD_TYPE: u8 = 1;
|
|
19
|
+
|
|
20
|
+
/// A writer for serializing data to a byte buffer.
|
|
21
|
+
///
|
|
22
|
+
/// The writer maintains an internal byte buffer and provides methods to write
|
|
23
|
+
/// various data types in big-endian format. All write operations return a
|
|
24
|
+
/// mutable reference to the writer, enabling method chaining.
|
|
25
|
+
///
|
|
26
|
+
/// # Example
|
|
27
|
+
/// ```ignore
|
|
28
|
+
/// let mut writer = BufferWriter::new(&env);
|
|
29
|
+
/// writer.write_u32(0x12345678)
|
|
30
|
+
/// .write_bool(true)
|
|
31
|
+
/// .write_bytes32(&bytes32);
|
|
32
|
+
/// let bytes = writer.to_bytes();
|
|
33
|
+
/// ```
|
|
34
|
+
pub struct BufferWriter {
|
|
35
|
+
buffer: Bytes,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
impl BufferWriter {
|
|
39
|
+
/// Create a new empty writer.
|
|
40
|
+
pub fn new(env: &Env) -> Self {
|
|
41
|
+
Self { buffer: Bytes::new(env) }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Create a new writer initialized with existing data.
|
|
45
|
+
pub fn from_bytes(buffer: Bytes) -> Self {
|
|
46
|
+
Self { buffer }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Generates: write_u8 (1 byte), write_u16 (2 bytes), write_u32 (4 bytes), write_u64 (8 bytes), write_u128 (16 bytes)
|
|
50
|
+
impl_write_uint!(write_u8, u8; write_u16, u16; write_u32, u32; write_u64, u64; write_u128, u128);
|
|
51
|
+
|
|
52
|
+
/// Write a boolean value to the buffer (true as 1, false as 0).
|
|
53
|
+
pub fn write_bool(&mut self, value: bool) -> &mut Self {
|
|
54
|
+
self.write_u8(if value { 1 } else { 0 })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Write an unsigned 256-bit integer in big-endian format.
|
|
58
|
+
pub fn write_u256(&mut self, value: U256) -> &mut Self {
|
|
59
|
+
self.buffer.append(&value.to_be_bytes());
|
|
60
|
+
self
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Write a byte slice to the buffer (appends without length prefix).
|
|
64
|
+
pub fn write_bytes(&mut self, bytes: &Bytes) -> &mut Self {
|
|
65
|
+
self.buffer.append(bytes);
|
|
66
|
+
self
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// Write a fixed-size BytesN<N> to the buffer.
|
|
70
|
+
pub fn write_bytes_n<const N: usize>(&mut self, bytes_n: &BytesN<N>) -> &mut Self {
|
|
71
|
+
self.buffer.extend_from_array(&bytes_n.to_array());
|
|
72
|
+
self
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Write an address type and payload to the buffer (33 bytes: 1 type + 32 payload).
|
|
76
|
+
pub fn write_address(&mut self, address: &Address) -> &mut Self {
|
|
77
|
+
let (payload_type, payload) = self.decompose_address(address);
|
|
78
|
+
self.write_u8(payload_type).write_bytes_n(&payload)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Write an address payload only to the buffer (32 bytes).
|
|
82
|
+
pub fn write_address_payload(&mut self, address: &Address) -> &mut Self {
|
|
83
|
+
let (_, payload) = self.decompose_address(address);
|
|
84
|
+
self.write_bytes_n(&payload)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Get the complete buffer as a Bytes, consuming the writer.
|
|
88
|
+
pub fn to_bytes(self) -> Bytes {
|
|
89
|
+
let Self { buffer } = self;
|
|
90
|
+
buffer
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Get the current length of the buffer.
|
|
94
|
+
pub fn len(&self) -> u32 {
|
|
95
|
+
self.buffer.len()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// Check if the buffer is empty.
|
|
99
|
+
pub fn is_empty(&self) -> bool {
|
|
100
|
+
self.buffer.is_empty()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// Get the environment from the buffer.
|
|
104
|
+
pub fn env(&self) -> &Env {
|
|
105
|
+
self.buffer.env()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// === Internal Functions ===
|
|
109
|
+
|
|
110
|
+
/// Decompose an address into its type byte and 32-byte payload.
|
|
111
|
+
fn decompose_address(&self, address: &Address) -> (u8, BytesN<32>) {
|
|
112
|
+
match address.to_payload().unwrap_or_panic(self.buffer.env(), BufferWriterError::InvalidAddressPayload) {
|
|
113
|
+
AddressPayload::AccountIdPublicKeyEd25519(p) => (ACCOUNT_PAYLOAD_TYPE, p),
|
|
114
|
+
AddressPayload::ContractIdHash(p) => (CONTRACT_PAYLOAD_TYPE, p),
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
use soroban_sdk::{assert_with_error, Bytes};
|
|
2
|
+
|
|
3
|
+
use crate::errors::BytesExtError;
|
|
4
|
+
|
|
5
|
+
/// Extension trait for `Bytes` to convert to fixed-size arrays
|
|
6
|
+
pub trait BytesExt {
|
|
7
|
+
/// Copies the entire bytes into a fixed-size array.
|
|
8
|
+
/// Panics if bytes length != N.
|
|
9
|
+
fn to_array<const N: usize>(&self) -> [u8; N];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
impl BytesExt for Bytes {
|
|
13
|
+
fn to_array<const N: usize>(&self) -> [u8; N] {
|
|
14
|
+
assert_with_error!(self.env(), self.len() == N as u32, BytesExtError::LengthMismatch);
|
|
15
|
+
let mut buf = [0u8; N];
|
|
16
|
+
self.copy_into_slice(&mut buf);
|
|
17
|
+
buf
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
use common_macros::contract_error;
|
|
2
|
+
|
|
3
|
+
#[contract_error]
|
|
4
|
+
pub enum BufferReaderError {
|
|
5
|
+
InvalidLength = 10000,
|
|
6
|
+
InvalidAddressPayload,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
#[contract_error]
|
|
10
|
+
pub enum BufferWriterError {
|
|
11
|
+
InvalidAddressPayload = 10100,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#[contract_error]
|
|
15
|
+
pub enum TtlError {
|
|
16
|
+
InvalidTtlConfig = 10200,
|
|
17
|
+
TtlConfigFrozen,
|
|
18
|
+
TtlConfigAlreadyFrozen,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#[contract_error]
|
|
22
|
+
pub enum OwnableError {
|
|
23
|
+
OwnerAlreadySet = 10300,
|
|
24
|
+
OwnerNotSet,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#[contract_error]
|
|
28
|
+
pub enum BytesExtError {
|
|
29
|
+
LengthMismatch = 10400,
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#![no_std]
|
|
2
|
+
|
|
3
|
+
pub mod buffer_reader;
|
|
4
|
+
pub mod buffer_writer;
|
|
5
|
+
pub mod bytes_ext;
|
|
6
|
+
pub mod errors;
|
|
7
|
+
pub mod option_ext;
|
|
8
|
+
pub mod ownable;
|
|
9
|
+
pub mod ttl;
|
|
10
|
+
|
|
11
|
+
#[cfg(test)]
|
|
12
|
+
mod tests;
|
|
13
|
+
|
|
14
|
+
#[cfg(any(test, feature = "testutils"))]
|
|
15
|
+
pub mod testing_utils;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
use soroban_sdk::{panic_with_error, Env};
|
|
2
|
+
|
|
3
|
+
/// Extension trait for `Option<T>` that provides Soroban-specific unwrapping utilities.
|
|
4
|
+
///
|
|
5
|
+
/// This trait extends the standard `Option` type with methods that integrate with
|
|
6
|
+
/// Soroban's error handling system, allowing for more descriptive panics when
|
|
7
|
+
/// unwrapping fails.
|
|
8
|
+
pub trait OptionExt<T> {
|
|
9
|
+
/// Unwraps the `Option`, returning the contained value if `Some`,
|
|
10
|
+
/// or panics with the provided error if `None`.
|
|
11
|
+
///
|
|
12
|
+
/// # Arguments
|
|
13
|
+
/// * `env` - The Soroban environment, required for error propagation.
|
|
14
|
+
/// * `error` - The error to emit if the `Option` is `None`. Must be convertible into a `soroban_sdk::Error`.
|
|
15
|
+
///
|
|
16
|
+
/// # Returns
|
|
17
|
+
/// The contained value if `Some`.
|
|
18
|
+
///
|
|
19
|
+
/// # Panics
|
|
20
|
+
/// Panics with the specified error if the `Option` is `None`.
|
|
21
|
+
fn unwrap_or_panic<E>(self, env: &Env, error: E) -> T
|
|
22
|
+
where
|
|
23
|
+
E: Into<soroban_sdk::Error>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
impl<T> OptionExt<T> for Option<T> {
|
|
27
|
+
fn unwrap_or_panic<E>(self, env: &Env, error: E) -> T
|
|
28
|
+
where
|
|
29
|
+
E: Into<soroban_sdk::Error>,
|
|
30
|
+
{
|
|
31
|
+
match self {
|
|
32
|
+
// Return the inner value if present
|
|
33
|
+
Some(val) => val,
|
|
34
|
+
// Panic with the provided error if None, using Soroban's error macro
|
|
35
|
+
None => panic_with_error!(env, error),
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|