@layerzerolabs/protocol-stellar-v2 0.2.19 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +795 -791
- package/.turbo/turbo-lint.log +325 -155
- package/.turbo/turbo-test.log +1398 -1277
- package/Cargo.lock +122 -111
- package/Cargo.toml +32 -16
- package/contracts/common-macros/Cargo.toml +7 -7
- package/contracts/common-macros/src/auth.rs +18 -37
- package/contracts/common-macros/src/contract_ttl.rs +18 -7
- package/contracts/common-macros/src/lib.rs +31 -14
- package/contracts/common-macros/src/lz_contract.rs +38 -7
- package/contracts/common-macros/src/storage.rs +251 -292
- package/contracts/common-macros/src/tests/contract_ttl.rs +1 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +6 -12
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +12 -17
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +2 -7
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +20 -14
- package/contracts/common-macros/src/tests/upgradeable.rs +26 -4
- package/contracts/common-macros/src/ttl_configurable.rs +2 -10
- package/contracts/common-macros/src/ttl_extendable.rs +2 -10
- package/contracts/common-macros/src/upgradeable.rs +61 -26
- package/contracts/common-macros/src/utils.rs +0 -9
- package/contracts/endpoint-v2/src/lib.rs +3 -2
- package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +2 -2
- package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +3 -3
- package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +4 -4
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +17 -5
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
- package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +2 -2
- package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +2 -2
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +6 -6
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +67 -37
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +5 -5
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +44 -54
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +7 -7
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +8 -8
- package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +4 -4
- package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +2 -2
- package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +2 -2
- package/contracts/layerzero-views/Cargo.toml +0 -1
- package/contracts/layerzero-views/src/layerzero_view.rs +1 -13
- package/contracts/macro-integration-tests/Cargo.toml +5 -15
- package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +48 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +170 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +154 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +338 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +435 -0
- package/contracts/macro-integration-tests/tests/runtime.rs +1 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.stderr +71 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.rs +10 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +38 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +96 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/minimal_contract.rs +64 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/struct_with_fields.rs +46 -0
- package/contracts/macro-integration-tests/tests/ui/ownable/fail/only_auth_missing_env.stderr +8 -0
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/only_auth_env_param_variants.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui_oapp.rs +11 -0
- package/contracts/message-libs/message-lib-common/Cargo.toml +0 -1
- package/contracts/message-libs/message-lib-common/src/errors.rs +1 -1
- package/contracts/message-libs/treasury/Cargo.toml +0 -2
- package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +2 -2
- package/contracts/message-libs/uln-302/src/events.rs +4 -0
- package/contracts/message-libs/uln-302/src/send_uln.rs +22 -6
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +21 -67
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +2 -2
- package/contracts/oapps/counter/Cargo.toml +5 -6
- package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
- package/contracts/oapps/counter/integration_tests/utils.rs +19 -12
- package/contracts/oapps/oapp/src/errors.rs +1 -1
- package/contracts/oapps/oapp/src/interfaces/mod.rs +3 -0
- package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +47 -0
- package/contracts/oapps/oapp/src/lib.rs +1 -0
- package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +4 -4
- package/contracts/oapps/oapp/src/oapp_core.rs +5 -5
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +12 -4
- package/contracts/oapps/oapp/src/oapp_receiver.rs +14 -9
- package/contracts/oapps/oapp/src/tests/mod.rs +4 -4
- package/contracts/oapps/oapp/src/tests/oapp_core.rs +223 -0
- package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +240 -0
- package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +381 -0
- package/contracts/oapps/oapp/src/tests/oapp_sender.rs +569 -0
- package/contracts/oapps/oapp-macros/Cargo.toml +8 -4
- package/contracts/oapps/oapp-macros/src/generators.rs +9 -34
- package/contracts/oapps/oapp-macros/src/lib.rs +3 -0
- package/contracts/oapps/oapp-macros/src/tests/mod.rs +2 -0
- package/contracts/oapps/oapp-macros/src/tests/oapp.rs +88 -0
- package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +86 -0
- package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +103 -0
- package/contracts/oapps/oft/integration-tests/utils.rs +28 -8
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +153 -75
- package/contracts/oapps/oft/src/extensions/pausable.rs +61 -12
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +198 -134
- package/contracts/oapps/oft/src/oft.rs +45 -50
- package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +1 -1
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +4 -26
- package/contracts/oapps/oft-core/Cargo.toml +1 -4
- package/contracts/oapps/oft-core/integration-tests/setup.rs +3 -3
- package/contracts/oapps/oft-core/integration-tests/utils.rs +21 -3
- package/contracts/oapps/oft-core/src/errors.rs +3 -2
- package/contracts/oapps/oft-core/src/events.rs +6 -0
- package/contracts/oapps/oft-core/src/lib.rs +1 -1
- package/contracts/oapps/oft-core/src/oft_core.rs +341 -246
- package/contracts/oapps/oft-core/src/storage.rs +7 -3
- package/contracts/oapps/oft-core/src/tests/mod.rs +1 -0
- package/contracts/oapps/oft-core/src/tests/test_decimals.rs +37 -2
- package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +2 -2
- package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +323 -0
- package/contracts/oapps/oft-core/src/tests/test_send.rs +2 -2
- package/contracts/oapps/oft-core/src/tests/test_utils.rs +61 -16
- package/contracts/upgrader/src/lib.rs +30 -57
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
- package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
- package/contracts/utils/Cargo.toml +0 -1
- package/contracts/utils/src/buffer_reader.rs +1 -0
- package/contracts/utils/src/errors.rs +4 -2
- package/contracts/utils/src/multisig.rs +17 -8
- package/contracts/utils/src/ownable.rs +6 -6
- package/contracts/utils/src/testing_utils.rs +124 -54
- package/contracts/utils/src/tests/multisig.rs +12 -12
- package/contracts/utils/src/tests/ownable.rs +6 -6
- package/contracts/utils/src/tests/testing_utils.rs +50 -167
- package/contracts/utils/src/tests/ttl_configurable.rs +5 -5
- package/contracts/utils/src/tests/upgradeable.rs +372 -175
- package/contracts/utils/src/ttl_configurable.rs +13 -7
- package/contracts/utils/src/upgradeable.rs +48 -23
- package/contracts/workers/dvn/Cargo.toml +6 -6
- package/contracts/workers/dvn/src/auth.rs +12 -42
- package/contracts/workers/dvn/src/dvn.rs +15 -40
- package/contracts/workers/dvn/src/errors.rs +0 -1
- package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
- package/contracts/workers/dvn/src/lib.rs +4 -3
- package/contracts/workers/dvn/src/tests/auth.rs +1 -1
- package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
- package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
- package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
- package/contracts/workers/dvn/src/tests/setup.rs +5 -9
- package/contracts/workers/dvn-fee-lib/Cargo.toml +2 -2
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +38 -22
- package/contracts/workers/dvn-fee-lib/src/lib.rs +12 -2
- package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +17 -16
- package/contracts/workers/executor/Cargo.toml +4 -0
- package/contracts/workers/executor/src/executor.rs +15 -36
- package/contracts/workers/executor/src/lib.rs +2 -2
- package/contracts/workers/executor/src/tests/auth.rs +394 -0
- package/contracts/workers/executor/src/tests/executor.rs +410 -0
- package/contracts/workers/executor/src/tests/mod.rs +3 -0
- package/contracts/workers/executor/src/tests/setup.rs +250 -0
- package/contracts/workers/executor-fee-lib/Cargo.toml +7 -1
- package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +62 -15
- package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
- package/contracts/workers/executor-fee-lib/src/lib.rs +11 -2
- package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
- package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
- package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
- package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
- package/contracts/workers/executor-helper/Cargo.toml +0 -1
- package/contracts/workers/executor-helper/src/lib.rs +3 -0
- package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
- package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
- package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
- package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
- package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
- package/contracts/workers/price-feed/Cargo.toml +7 -1
- package/contracts/workers/price-feed/src/events.rs +1 -1
- package/contracts/workers/price-feed/src/lib.rs +12 -4
- package/contracts/workers/price-feed/src/price_feed.rs +5 -21
- package/contracts/workers/price-feed/src/storage.rs +1 -1
- package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
- package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
- package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
- package/contracts/workers/price-feed/src/types.rs +1 -1
- package/contracts/workers/worker/src/errors.rs +1 -4
- package/contracts/workers/worker/src/lib.rs +0 -2
- package/contracts/workers/worker/src/storage.rs +32 -29
- package/contracts/workers/worker/src/tests/setup.rs +2 -8
- package/contracts/workers/worker/src/tests/worker.rs +96 -74
- package/contracts/workers/worker/src/worker.rs +75 -75
- package/docs/error-spec.md +55 -0
- package/docs/layerzero-v2-on-stellar.md +447 -0
- package/docs/oapp-guide.md +212 -0
- package/docs/oft-guide.md +314 -0
- package/package.json +3 -3
- package/sdk/.turbo/turbo-test.log +268 -263
- package/sdk/dist/generated/bml.d.ts +12 -4
- package/sdk/dist/generated/bml.js +9 -7
- package/sdk/dist/generated/counter.d.ts +306 -298
- package/sdk/dist/generated/counter.js +48 -46
- package/sdk/dist/generated/dvn.d.ts +450 -411
- package/sdk/dist/generated/dvn.js +66 -64
- package/sdk/dist/generated/dvn_fee_lib.d.ts +294 -338
- package/sdk/dist/generated/dvn_fee_lib.js +33 -64
- package/sdk/dist/generated/endpoint.d.ts +108 -100
- package/sdk/dist/generated/endpoint.js +21 -19
- package/sdk/dist/generated/executor.d.ts +414 -370
- package/sdk/dist/generated/executor.js +58 -55
- package/sdk/dist/generated/executor_fee_lib.d.ts +333 -377
- package/sdk/dist/generated/executor_fee_lib.js +34 -65
- package/sdk/dist/generated/executor_helper.d.ts +26 -190
- package/sdk/dist/generated/executor_helper.js +23 -28
- package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
- package/sdk/dist/generated/layerzero_view.js +294 -0
- package/sdk/dist/generated/oft.d.ts +408 -385
- package/sdk/dist/generated/oft.js +89 -92
- package/sdk/dist/generated/price_feed.d.ts +385 -429
- package/sdk/dist/generated/price_feed.js +50 -81
- package/sdk/dist/generated/sml.d.ts +108 -100
- package/sdk/dist/generated/sml.js +21 -19
- package/sdk/dist/generated/treasury.d.ts +108 -100
- package/sdk/dist/generated/treasury.js +21 -19
- package/sdk/dist/generated/uln302.d.ts +108 -100
- package/sdk/dist/generated/uln302.js +23 -21
- package/sdk/dist/generated/upgrader.d.ts +189 -18
- package/sdk/dist/generated/upgrader.js +84 -4
- package/sdk/dist/index.d.ts +1 -0
- package/sdk/dist/index.js +2 -0
- package/sdk/package.json +1 -1
- package/sdk/src/index.ts +3 -0
- package/sdk/test/oft-sml.test.ts +4 -4
- package/sdk/test/suites/localnet.ts +84 -20
- package/sdk/test/upgrader.test.ts +2 -3
- package/tools/ts-bindings-gen/src/main.rs +2 -1
- package/contracts/ERROR_SPEC.md +0 -44
- package/contracts/endpoint-v2/ARCHITECTURE.md +0 -233
- package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +0 -175
- package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +0 -212
- package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +0 -153
- package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +0 -294
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# LayerZero V2 on Stellar
|
|
2
|
+
|
|
3
|
+
This document provides a comprehensive guide to LayerZero V2's implementation on
|
|
4
|
+
the Stellar blockchain using Soroban smart contracts.
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
LayerZero V2 on Stellar enables cross-chain messaging between Stellar and other
|
|
9
|
+
blockchains. Built on Soroban (Stellar's smart contract platform) using Rust, it
|
|
10
|
+
follows a modular, plugin-based architecture that maintains compatibility with
|
|
11
|
+
LayerZero's V2 protocol design while adapting to Stellar's unique
|
|
12
|
+
characteristics.
|
|
13
|
+
|
|
14
|
+
### Key components
|
|
15
|
+
|
|
16
|
+
- **EndpointV2**: Central hub for all cross-chain messaging operations
|
|
17
|
+
- **Message libraries**: Pluggable verification logic (ULN302, SimpleMessageLib)
|
|
18
|
+
- **Workers**: DVNs (Decentralized Verifier Networks) and executors
|
|
19
|
+
- **OApps**: Omnichain applications that leverage the protocol
|
|
20
|
+
- **OFT**: Omnichain Fungible Token standard for cross-chain token transfers
|
|
21
|
+
|
|
22
|
+
## Architecture
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ OApp / OFT │
|
|
27
|
+
│ (Omnichain Application Layer) │
|
|
28
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
29
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
30
|
+
│ EndpointV2 │
|
|
31
|
+
│ (Central Messaging Hub) │
|
|
32
|
+
│ ┌─────────────────┐ ┌──────────────────┐ ┌────────────────────────────┐ │
|
|
33
|
+
│ │ MessageLib │ │ MessagingChannel │ │ MessagingComposer │ │
|
|
34
|
+
│ │ Manager │ │ (Nonce/Payload) │ │ (Multi-stage Execution) │ │
|
|
35
|
+
│ └─────────────────┘ └──────────────────┘ └────────────────────────────┘ │
|
|
36
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
37
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
38
|
+
│ Message Libraries │
|
|
39
|
+
│ ┌──────────────────────────────────┐ ┌─────────────────────────────────┐ │
|
|
40
|
+
│ │ ULN302 │ │ SimpleMessageLib │ │
|
|
41
|
+
│ │ (Ultra Light Node - Production) │ │ (Testing/Basic) │ │
|
|
42
|
+
│ └──────────────────────────────────┘ └─────────────────────────────────┘ │
|
|
43
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
44
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
45
|
+
│ Workers │
|
|
46
|
+
│ ┌────────────────────────────┐ ┌────────────────────────────────────┐ │
|
|
47
|
+
│ │ DVN │ │ Executor │ │
|
|
48
|
+
│ │ (Message Verification) │ │ (Message Execution) │ │
|
|
49
|
+
│ └────────────────────────────┘ └────────────────────────────────────┘ │
|
|
50
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Core contracts
|
|
54
|
+
|
|
55
|
+
### EndpointV2
|
|
56
|
+
|
|
57
|
+
The central contract managing all cross-chain messaging operations.
|
|
58
|
+
|
|
59
|
+
**Location**: `contracts/endpoint-v2/`
|
|
60
|
+
|
|
61
|
+
**Key responsibilities**:
|
|
62
|
+
|
|
63
|
+
- Quote messaging fees
|
|
64
|
+
- Send cross-chain messages
|
|
65
|
+
- Verify inbound messages
|
|
66
|
+
- Clear and deliver verified messages
|
|
67
|
+
- Manage message libraries
|
|
68
|
+
- Track nonce ordering for message sequencing
|
|
69
|
+
|
|
70
|
+
**Internal modules**:
|
|
71
|
+
|
|
72
|
+
| Module | Purpose |
|
|
73
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------------- |
|
|
74
|
+
| `message_lib_manager.rs` | Library registration, selection, and configuration. Tracks default/per-OApp libraries per EID. |
|
|
75
|
+
| `messaging_channel.rs` | Nonce tracking, payload hash storage/verification, message state transitions (verify → receive → clear). |
|
|
76
|
+
| `messaging_composer.rs` | Manages compose message queues for multi-stage execution between OApp and Composers. |
|
|
77
|
+
| `util.rs` | Public utilities: `compute_guid()`, `build_payload()`, `keccak256()` for message processing. |
|
|
78
|
+
|
|
79
|
+
**Design patterns**:
|
|
80
|
+
|
|
81
|
+
- **Interfaces as library exports**: External contracts depend on trait
|
|
82
|
+
definitions only, controlled by the `library` feature flag
|
|
83
|
+
- **Interface composition**: `ILayerZeroEndpointV2` composes
|
|
84
|
+
`IMessageLibManager`, `IMessagingChannel`, and `IMessagingComposer`
|
|
85
|
+
- **Client generation**: `#[contractclient]` macro generates type-safe client
|
|
86
|
+
wrappers for cross-contract calls
|
|
87
|
+
|
|
88
|
+
### ULN302 (Ultra Light Node)
|
|
89
|
+
|
|
90
|
+
The primary message library implementing verification through DVNs and execution
|
|
91
|
+
through executors.
|
|
92
|
+
|
|
93
|
+
**Location**: `contracts/message-libs/uln-302/`
|
|
94
|
+
|
|
95
|
+
### DVN (Decentralized Verifier Network)
|
|
96
|
+
|
|
97
|
+
Provides cryptographic attestations that messages were properly sent on the
|
|
98
|
+
source chain.
|
|
99
|
+
|
|
100
|
+
**Location**: `contracts/workers/dvn/`
|
|
101
|
+
|
|
102
|
+
**Features**:
|
|
103
|
+
|
|
104
|
+
- Multisig-based verification using secp256k1 signatures
|
|
105
|
+
- Custom Soroban account interface for transaction signing
|
|
106
|
+
- Destination-specific configuration
|
|
107
|
+
- Fee calculation based on quorum size and gas costs
|
|
108
|
+
|
|
109
|
+
### Executor
|
|
110
|
+
|
|
111
|
+
Executes verified messages on the destination chain.
|
|
112
|
+
|
|
113
|
+
**Location**: `contracts/workers/executor/`
|
|
114
|
+
|
|
115
|
+
**Features**:
|
|
116
|
+
|
|
117
|
+
- Message delivery to receiving OApps
|
|
118
|
+
- Native token drops to addresses
|
|
119
|
+
- Destination-specific configuration
|
|
120
|
+
- Fee calculation based on message size and execution parameters
|
|
121
|
+
|
|
122
|
+
### OApp (Omnichain Application)
|
|
123
|
+
|
|
124
|
+
Base framework for building cross-chain applications.
|
|
125
|
+
|
|
126
|
+
**Location**: `contracts/oapps/oapp/`
|
|
127
|
+
|
|
128
|
+
**Key traits**:
|
|
129
|
+
|
|
130
|
+
| Trait | Purpose |
|
|
131
|
+
| -------------------- | ------------------------------------------------- |
|
|
132
|
+
| `OAppCore` | Foundation: peer management, endpoint reference |
|
|
133
|
+
| `OAppSenderInternal` | Internal helper for sending cross-chain messages |
|
|
134
|
+
| `OAppReceiver` | Public receiver interface, payload clearing |
|
|
135
|
+
| `LzReceiveInternal` | Application message handling (**must implement**) |
|
|
136
|
+
| `OAppOptionsType3` | Enforced execution options management |
|
|
137
|
+
|
|
138
|
+
### OFT (Omnichain Fungible Token)
|
|
139
|
+
|
|
140
|
+
Standardized cross-chain token bridge implementation.
|
|
141
|
+
|
|
142
|
+
**Location**: `contracts/oapps/oft/`
|
|
143
|
+
|
|
144
|
+
**Key traits**:
|
|
145
|
+
|
|
146
|
+
| Trait | Purpose |
|
|
147
|
+
| ------------- | ----------------------------------------------------- |
|
|
148
|
+
| `OFTCore` | Public interface: `send()`, `quote_send()`, `token()` |
|
|
149
|
+
| `OFTInternal` | Internal implementation: `__debit()`, `__credit()` |
|
|
150
|
+
|
|
151
|
+
**Features**:
|
|
152
|
+
|
|
153
|
+
- Token type flexibility (LockUnlock or MintBurn)
|
|
154
|
+
- Fee extension for outbound transfers
|
|
155
|
+
- Pausable extension
|
|
156
|
+
- Rate limiter extension
|
|
157
|
+
- Dust removal and slippage protection
|
|
158
|
+
|
|
159
|
+
## Messaging flow
|
|
160
|
+
|
|
161
|
+
### Sending a message
|
|
162
|
+
|
|
163
|
+
```mermaid
|
|
164
|
+
sequenceDiagram
|
|
165
|
+
participant OApp
|
|
166
|
+
participant Endpoint as EndpointV2
|
|
167
|
+
participant SendLib as SendLib (ULN302)
|
|
168
|
+
participant DVN
|
|
169
|
+
participant Executor
|
|
170
|
+
|
|
171
|
+
OApp->>Endpoint: quote(params)
|
|
172
|
+
Endpoint-->>OApp: MessagingFee
|
|
173
|
+
|
|
174
|
+
OApp->>Endpoint: send(params, refund_address)
|
|
175
|
+
Note over Endpoint: Increment outbound nonce
|
|
176
|
+
Note over Endpoint: Create GUID = keccak256(nonce, src_eid, sender, dst_eid, receiver)
|
|
177
|
+
|
|
178
|
+
Endpoint->>SendLib: send(packet, options)
|
|
179
|
+
SendLib->>DVN: assignJob(packet_header, payload_hash, confirmations)
|
|
180
|
+
SendLib->>Executor: assignJob(packet_header, payload_hash, options)
|
|
181
|
+
Note over SendLib: Calculate Treasury fee
|
|
182
|
+
SendLib-->>Endpoint: (fee recipients, fees)
|
|
183
|
+
|
|
184
|
+
Note over Endpoint: Distribute fees to workers
|
|
185
|
+
Endpoint-->>OApp: MessagingReceipt
|
|
186
|
+
Note over Endpoint: Emit PacketSent event
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Receiving a message
|
|
190
|
+
|
|
191
|
+
```mermaid
|
|
192
|
+
sequenceDiagram
|
|
193
|
+
participant DVN
|
|
194
|
+
participant ReceiveLib as ReceiveLib (ULN302)
|
|
195
|
+
participant Endpoint as EndpointV2
|
|
196
|
+
participant Executor
|
|
197
|
+
participant OApp
|
|
198
|
+
|
|
199
|
+
rect rgb(240, 248, 255)
|
|
200
|
+
Note over DVN, Endpoint: Step 1: Verification
|
|
201
|
+
Note over DVN: Monitor source chain for PacketSent
|
|
202
|
+
Note over DVN: Wait for block confirmations
|
|
203
|
+
DVN->>ReceiveLib: verify(packet_header, payload_hash)
|
|
204
|
+
Note over ReceiveLib: Record DVN attestation
|
|
205
|
+
Note over ReceiveLib: Check if quorum reached
|
|
206
|
+
ReceiveLib->>Endpoint: verify(origin, receiver, payload_hash)
|
|
207
|
+
Note over Endpoint: Store payload_hash
|
|
208
|
+
Note over Endpoint: Emit PacketVerified event
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
rect rgb(240, 255, 240)
|
|
212
|
+
Note over Executor, OApp: Step 2: Execution
|
|
213
|
+
Executor->>OApp: lz_receive(origin, guid, message, extra_data)
|
|
214
|
+
OApp->>Endpoint: clear(origin, guid, message)
|
|
215
|
+
Note over Endpoint: Validate payload against stored hash
|
|
216
|
+
Note over Endpoint: Emit PacketDelivered event
|
|
217
|
+
Endpoint-->>OApp: (success)
|
|
218
|
+
Note over OApp: Execute __lz_receive() logic
|
|
219
|
+
end
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Stellar-specific considerations
|
|
223
|
+
|
|
224
|
+
Two core differences between Soroban and EVM require protocol-level adaptations:
|
|
225
|
+
|
|
226
|
+
1. Stellar's variable-length address model differs from LayerZero's fixed
|
|
227
|
+
bytes32 address abstraction
|
|
228
|
+
2. Soroban's Time-To-Live (TTL)-based storage model requires active state
|
|
229
|
+
maintenance, unlike EVM's persistent storage
|
|
230
|
+
|
|
231
|
+
### Constraint 1: bytes32 address format mismatch
|
|
232
|
+
|
|
233
|
+
LayerZero V2 standardizes all cross-chain addresses using bytes32. Stellar uses
|
|
234
|
+
StrKey-encoded addresses of different types:
|
|
235
|
+
|
|
236
|
+
| Address Type | Structure | Usage |
|
|
237
|
+
| ------------ | ------------------------------------------------------ | ------------------------ |
|
|
238
|
+
| G-Address | 1-byte version + 32-byte public key + 2-byte checksum | EOAs (Ed25519 key pairs) |
|
|
239
|
+
| C-Address | 1-byte version + 32-byte contract ID + 2-byte checksum | Soroban smart contracts |
|
|
240
|
+
| M-Address | G-address payload + 64-bit ID (exceeds 32 bytes) | Exchange sub-accounts |
|
|
241
|
+
|
|
242
|
+
**Key observation**: G-Address and C-Address share the same 32-byte payload
|
|
243
|
+
structure, and the payload alone is guaranteed to be unique across both types.
|
|
244
|
+
|
|
245
|
+
**Solution: Deterministic address resolution**
|
|
246
|
+
|
|
247
|
+
All bytes32-encoded addresses are resolved at execution time:
|
|
248
|
+
|
|
249
|
+
1. **OApp & Composer addresses**: The bytes32 value is interpreted directly as a
|
|
250
|
+
Soroban contract ID and converted to a C-address.
|
|
251
|
+
|
|
252
|
+
2. **Native drop & OFT receiver addresses**: Contract-first detection is
|
|
253
|
+
applied:
|
|
254
|
+
- Convert the bytes32 payload to a C-address
|
|
255
|
+
- If a contract exists at that address, treat as C-address
|
|
256
|
+
- Otherwise, treat as G-address
|
|
257
|
+
|
|
258
|
+
This resolution is deterministic and safe. Soroban guarantees that a deployed
|
|
259
|
+
contract address cannot correspond to a valid G-address private key, eliminating
|
|
260
|
+
ambiguity.
|
|
261
|
+
|
|
262
|
+
### Constraint 2: TTL-based storage model
|
|
263
|
+
|
|
264
|
+
All contract data entries on Soroban have a TTL. When TTL expires, data becomes
|
|
265
|
+
archived and inaccessible (but always restorable).
|
|
266
|
+
|
|
267
|
+
**Challenges**:
|
|
268
|
+
|
|
269
|
+
- **Cost impact**: The Endpoint contract (~60 KB) costs ~3.0 USD/month to keep
|
|
270
|
+
alive. Restoration after archival (~4 months bump) costs ~12 USD.
|
|
271
|
+
- **Execution variability**: TTL extension during `lzReceive` introduces
|
|
272
|
+
additional fees and risk of out-of-gas failures.
|
|
273
|
+
- **OApp-induced operations**: OApps (e.g., SAC tokens) may perform their own
|
|
274
|
+
TTL bumps, adding unpredictable overhead.
|
|
275
|
+
|
|
276
|
+
**Solution: Hybrid TTL extension strategy**
|
|
277
|
+
|
|
278
|
+
LayerZero adopts a hybrid approach combining Self-Extension with Client
|
|
279
|
+
Extension:
|
|
280
|
+
|
|
281
|
+
1. **Self-Extension (default)**: Contracts automatically extend TTL for storage
|
|
282
|
+
entries when accessed if remaining TTL falls below a configured threshold.
|
|
283
|
+
This is autonomous and requires no external maintenance.
|
|
284
|
+
|
|
285
|
+
2. **Client Extension (selective)**: For low-activity periods, off-chain
|
|
286
|
+
services or sealer-assisted extension can keep critical components (Endpoint,
|
|
287
|
+
ULN) alive without imposing costs on users.
|
|
288
|
+
|
|
289
|
+
**Configurable TTL parameters**: Unlike typical Soroban apps that hardcode TTL
|
|
290
|
+
values, LayerZero exposes TTL thresholds and extension targets as configurable
|
|
291
|
+
values. This follows Stellar team recommendations, as storage fees and network
|
|
292
|
+
constraints may evolve.
|
|
293
|
+
|
|
294
|
+
**Governance safeguards**:
|
|
295
|
+
|
|
296
|
+
- Hard upper cap on extension targets (e.g., 1 year) to prevent excessive fees
|
|
297
|
+
- TTL parameters can be permanently frozen once the ecosystem stabilizes
|
|
298
|
+
|
|
299
|
+
### Constraint 3: Reentrancy prohibition
|
|
300
|
+
|
|
301
|
+
Soroban prohibits reentrancy—a contract cannot call itself, directly or
|
|
302
|
+
indirectly, within the same transaction. This fundamental difference from EVM
|
|
303
|
+
requires rethinking several LayerZero patterns.
|
|
304
|
+
|
|
305
|
+
#### Impact on DVN design
|
|
306
|
+
|
|
307
|
+
On EVM, the DVN contract uses a **self-call pattern** for multisig-authorized
|
|
308
|
+
self-configuration (e.g., setting destination configs, updating signers). An
|
|
309
|
+
admin submits M-of-N signatures over a set of calls to the DVN. The DVN verifies
|
|
310
|
+
the signatures, then calls itself to execute the configuration changes. For
|
|
311
|
+
external calls like `ULN302.verify()`, the DVN simply calls the target contract
|
|
312
|
+
directly after signature verification.
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
EVM DVN Flow (self-configuration):
|
|
316
|
+
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
317
|
+
│ Admin │───►│ DVN │───►│ DVN │ (self-call after
|
|
318
|
+
│ │ │ (verify) │ │ (execute) │ sig verification)
|
|
319
|
+
└─────────────┘ └─────────────┘ └─────────────┘
|
|
320
|
+
|
|
321
|
+
EVM DVN Flow (external calls):
|
|
322
|
+
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
323
|
+
│ Admin │───►│ DVN │───►│ ULN302 │ (direct call after
|
|
324
|
+
│ │ │ (verify) │ │ .verify() │ sig verification)
|
|
325
|
+
└─────────────┘ └─────────────┘ └─────────────┘
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
The self-call pattern for configuration fails on Soroban because the DVN cannot
|
|
329
|
+
call itself. The solution is to implement DVN as an **Abstract Account** (custom
|
|
330
|
+
account). Soroban's custom account interface allows contracts to define
|
|
331
|
+
authorization logic via `__check_auth`. Instead of self-calling, the DVN
|
|
332
|
+
authorizes calls made on its behalf—both self-configuration and external calls:
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
Stellar DVN Flow (Abstract Account):
|
|
336
|
+
┌─────────────┐ ┌─────────────┐
|
|
337
|
+
│ Admin │───►│ ULN302 │ DVN authorizes via __check_auth
|
|
338
|
+
│ (submits │ │ .verify() │ (signature verification happens
|
|
339
|
+
│ tx with │ │ │ in the auth context, not as
|
|
340
|
+
│ DVN auth) │ │ │ a separate call)
|
|
341
|
+
└─────────────┘ └─────────────┘
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
The DVN's `__check_auth` validates:
|
|
345
|
+
|
|
346
|
+
- Verifier ID (VID) matches
|
|
347
|
+
- Authorization hasn't expired
|
|
348
|
+
- Admin signature is valid (Ed25519) — except for `set_admin` calls
|
|
349
|
+
- Call data hash hasn't been replayed
|
|
350
|
+
- M-of-N secp256k1 signatures from the quorum
|
|
351
|
+
|
|
352
|
+
#### Impact on executor design
|
|
353
|
+
|
|
354
|
+
LayerZero supports a common cross-chain pattern called **ABA messaging**—an
|
|
355
|
+
OApp on chain B receives a message from chain A and atomically sends a response
|
|
356
|
+
back to chain A within the same transaction:
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
ABA Pattern:
|
|
360
|
+
Chain A Chain B
|
|
361
|
+
┌───────┐ ┌───────┐
|
|
362
|
+
│ OApp │ ──── msg1 ─────► │ OApp │
|
|
363
|
+
│ │ ◄─── msg2 ───── │ │ (msg2 sent in lz_receive handler)
|
|
364
|
+
└───────┘ └───────┘
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
If the executor were a regular contract that calls the OApp, it would be locked
|
|
368
|
+
during the receive flow. When the OApp attempts to send a message back (which
|
|
369
|
+
requires interacting with the executor for fee quoting), the transaction would
|
|
370
|
+
fail due to reentrancy:
|
|
371
|
+
|
|
372
|
+
```
|
|
373
|
+
❌ Regular Contract Executor (fails ABA):
|
|
374
|
+
┌──────────┐ ┌───────┐ ┌──────────┐ ┌─────────────┐
|
|
375
|
+
│ Executor │───►│ OApp │───►│ Endpoint │───►│ Executor │ BLOCKED!
|
|
376
|
+
│ .call() │ │ │ │ .send() │ │.assign_job()| (reentrancy)
|
|
377
|
+
└──────────┘ └───────┘ └──────────┘ └─────────────┘
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
By implementing executor as an **Abstract Account**, the executor doesn't
|
|
381
|
+
"call" the OApp—it authorizes the OApp's `lz_receive` invocation. The executor
|
|
382
|
+
contract remains accessible for the send flow:
|
|
383
|
+
|
|
384
|
+
```
|
|
385
|
+
✓ Abstract Account Executor (supports ABA):
|
|
386
|
+
┌───────┐ ┌──────────┐
|
|
387
|
+
│ OApp │ ◄───────── executor auth ──────────── │ Executor │ (not in call stack,
|
|
388
|
+
│ │ via __check_auth │ AA │ remains accessible)
|
|
389
|
+
│ │ ─► Endpoint.send() ─► .assign_job() ─► │ │ ✓ Works!
|
|
390
|
+
└───────┘ └──────────┘
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
#### Impact on message delivery design
|
|
394
|
+
|
|
395
|
+
The same reentrancy constraint affects how messages are delivered to OApps.
|
|
396
|
+
|
|
397
|
+
**EVM approach (push mode)**: The endpoint is the entry point. After verifying
|
|
398
|
+
and clearing the payload, the endpoint calls the OApp's `lzReceive`:
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
EVM Push Mode:
|
|
402
|
+
Executor ──► Endpoint.lzReceive() ──► OApp.lzReceive()
|
|
403
|
+
│
|
|
404
|
+
└── (clear payload, then call OApp)
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
This fails on Soroban for ABA messaging. If the endpoint calls the OApp, the
|
|
408
|
+
endpoint is locked. When the OApp tries to send a response message, it cannot
|
|
409
|
+
call back into the endpoint:
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
❌ Push Mode on Stellar (fails ABA):
|
|
413
|
+
Executor ──► Endpoint.lz_receive() ──► OApp ──► Endpoint.send() BLOCKED!
|
|
414
|
+
(reentrancy)
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Stellar approach (pull mode)**: The OApp is the entry point. The executor
|
|
418
|
+
authorizes the OApp's `lz_receive` call, and the OApp pulls verification from
|
|
419
|
+
the endpoint by calling `clear`:
|
|
420
|
+
|
|
421
|
+
```
|
|
422
|
+
✓ Pull Mode on Stellar (supports ABA):
|
|
423
|
+
Executor auth ──► OApp.lz_receive() ──► Endpoint.clear()
|
|
424
|
+
│
|
|
425
|
+
└──► Endpoint.send() ✓ Works!
|
|
426
|
+
(endpoint not in call stack)
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Summary of reentrancy adaptations**:
|
|
430
|
+
|
|
431
|
+
| Component | EVM Pattern | Stellar Pattern | Reason |
|
|
432
|
+
| --------- | -------------------------------- | ------------------------------------ | ------------------- |
|
|
433
|
+
| DVN | Self-call after sig verification | Abstract Account with `__check_auth` | Cannot self-call |
|
|
434
|
+
| Executor | Regular contract calls OApp | Abstract Account authorizes OApp | ABA pattern support |
|
|
435
|
+
| Delivery | Push (Endpoint → OApp) | Pull (OApp → Endpoint.clear) | ABA pattern support |
|
|
436
|
+
|
|
437
|
+
## Building OApps and OFTs
|
|
438
|
+
|
|
439
|
+
- [oapp-guide.md](oapp-guide.md) - Building Omnichain Applications using the
|
|
440
|
+
OApp framework, macros, and traits
|
|
441
|
+
- [oft-guide.md](oft-guide.md) - Building Omnichain Fungible Tokens with
|
|
442
|
+
MintBurn/LockUnlock strategies and extensions
|
|
443
|
+
|
|
444
|
+
## Error codes
|
|
445
|
+
|
|
446
|
+
See [error-spec.md](error-spec.md) for the error code allocation strategy and
|
|
447
|
+
detailed specifications.
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Building OApps on Stellar
|
|
2
|
+
|
|
3
|
+
This guide explains how to build Omnichain Applications (OApps) using the LayerZero V2 framework on Stellar.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
An OApp is a cross-chain application that can send and receive messages through LayerZero. The framework provides:
|
|
8
|
+
|
|
9
|
+
- **OAppCore**: Foundation for all OApp functionality (peer management, endpoint access)
|
|
10
|
+
- **OAppSenderInternal**: Enables sending cross-chain messages
|
|
11
|
+
- **OAppReceiver**: Handles incoming cross-chain messages
|
|
12
|
+
- **LzReceiveInternal**: Application-specific message handling logic
|
|
13
|
+
- **OAppOptionsType3**: Manages enforced options for message execution
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
The `#[oapp]` macro provides the simplest way to create an OApp:
|
|
18
|
+
|
|
19
|
+
```rust
|
|
20
|
+
use oapp::oapp_receiver::LzReceiveInternal;
|
|
21
|
+
use oapp_macros::oapp;
|
|
22
|
+
|
|
23
|
+
#[oapp]
|
|
24
|
+
pub struct MyOApp;
|
|
25
|
+
|
|
26
|
+
impl LzReceiveInternal for MyOApp {
|
|
27
|
+
fn __lz_receive(
|
|
28
|
+
env: &Env,
|
|
29
|
+
origin: &Origin,
|
|
30
|
+
guid: &BytesN<32>,
|
|
31
|
+
message: &Bytes,
|
|
32
|
+
extra_data: &Bytes,
|
|
33
|
+
executor: &Address,
|
|
34
|
+
value: i128,
|
|
35
|
+
) {
|
|
36
|
+
// Your message handling logic here
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The macro automatically generates:
|
|
42
|
+
|
|
43
|
+
- `#[contract]` attribute
|
|
44
|
+
- `#[ownable]` trait implementation
|
|
45
|
+
- `OAppCore` implementation
|
|
46
|
+
- `OAppSenderInternal` implementation
|
|
47
|
+
- `OAppReceiver` implementation
|
|
48
|
+
- `OAppOptionsType3` implementation
|
|
49
|
+
|
|
50
|
+
## Initialization
|
|
51
|
+
|
|
52
|
+
Initialize your OApp in the constructor:
|
|
53
|
+
|
|
54
|
+
```rust
|
|
55
|
+
use oapp::oapp_core::initialize_oapp;
|
|
56
|
+
|
|
57
|
+
#[contract_impl]
|
|
58
|
+
impl MyOApp {
|
|
59
|
+
pub fn __constructor(env: &Env, owner: &Address, endpoint: &Address, delegate: &Address) {
|
|
60
|
+
initialize_oapp::<Self>(env, owner, endpoint, &Some(delegate.clone()));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The `initialize_oapp` function:
|
|
66
|
+
|
|
67
|
+
1. Sets the contract owner
|
|
68
|
+
2. Stores the LayerZero endpoint address
|
|
69
|
+
3. Optionally sets a delegate on the endpoint
|
|
70
|
+
|
|
71
|
+
## Peer management
|
|
72
|
+
|
|
73
|
+
Before sending or receiving messages, configure peers for each destination chain:
|
|
74
|
+
|
|
75
|
+
```rust
|
|
76
|
+
// Set a peer (owner only)
|
|
77
|
+
oapp.set_peer(dst_eid, peer_address_bytes32);
|
|
78
|
+
|
|
79
|
+
// Remove a peer
|
|
80
|
+
oapp.set_peer(dst_eid, None);
|
|
81
|
+
|
|
82
|
+
// Query a peer
|
|
83
|
+
let peer = oapp.peer(dst_eid);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Peers are stored as `BytesN<32>` to maintain cross-chain address compatibility.
|
|
87
|
+
|
|
88
|
+
## Sending messages
|
|
89
|
+
|
|
90
|
+
Use the internal sender methods to send cross-chain messages:
|
|
91
|
+
|
|
92
|
+
```rust
|
|
93
|
+
use oapp::oapp_sender::OAppSenderInternal;
|
|
94
|
+
|
|
95
|
+
impl MyOApp {
|
|
96
|
+
pub fn send_message(env: &Env, caller: &Address, dst_eid: u32, message: &Bytes, options: &Bytes, fee: &MessagingFee) {
|
|
97
|
+
caller.require_auth();
|
|
98
|
+
|
|
99
|
+
// Send the message (handles fee payment automatically)
|
|
100
|
+
Self::__lz_send(env, dst_eid, message, options, caller, fee, caller);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
pub fn quote(env: &Env, dst_eid: u32, message: &Bytes, options: &Bytes, pay_in_zro: bool) -> MessagingFee {
|
|
104
|
+
Self::__quote(env, dst_eid, message, options, pay_in_zro)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The `__lz_send` method:
|
|
110
|
+
|
|
111
|
+
1. Transfers the native fee from the payer to the endpoint
|
|
112
|
+
2. Transfers the ZRO fee if applicable
|
|
113
|
+
3. Looks up the peer for the destination
|
|
114
|
+
4. Calls the endpoint's `send` function
|
|
115
|
+
|
|
116
|
+
## Receiving messages
|
|
117
|
+
|
|
118
|
+
Implement `LzReceiveInternal` to handle incoming messages:
|
|
119
|
+
|
|
120
|
+
```rust
|
|
121
|
+
impl LzReceiveInternal for MyOApp {
|
|
122
|
+
fn __lz_receive(
|
|
123
|
+
env: &Env,
|
|
124
|
+
origin: &Origin, // Contains src_eid, sender, nonce
|
|
125
|
+
guid: &BytesN<32>, // Unique message identifier
|
|
126
|
+
message: &Bytes, // The message payload
|
|
127
|
+
extra_data: &Bytes, // Additional data from executor
|
|
128
|
+
executor: &Address, // Executor who delivered the message
|
|
129
|
+
value: i128, // Native token value sent with message
|
|
130
|
+
) {
|
|
131
|
+
// Your message handling logic
|
|
132
|
+
// Note: clear_payload_and_transfer is called automatically before this
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The default `lz_receive` flow:
|
|
138
|
+
|
|
139
|
+
1. Requires executor authorization
|
|
140
|
+
2. Transfers native value from executor to OApp (if any)
|
|
141
|
+
3. Verifies the sender matches the configured peer
|
|
142
|
+
4. Clears the payload from the endpoint
|
|
143
|
+
5. Calls your `__lz_receive` implementation
|
|
144
|
+
|
|
145
|
+
## Custom implementations
|
|
146
|
+
|
|
147
|
+
Use `#[oapp(custom = [...])]` to override default behavior:
|
|
148
|
+
|
|
149
|
+
### Custom receiver (ordered delivery)
|
|
150
|
+
|
|
151
|
+
```rust
|
|
152
|
+
#[oapp(custom = [receiver])]
|
|
153
|
+
pub struct MyOrderedOApp;
|
|
154
|
+
|
|
155
|
+
impl LzReceiveInternal for MyOrderedOApp {
|
|
156
|
+
fn __lz_receive(env: &Env, origin: &Origin, ...) {
|
|
157
|
+
// Your logic here
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#[contract_impl(contracttrait)]
|
|
162
|
+
impl OAppReceiver for MyOrderedOApp {
|
|
163
|
+
fn next_nonce(env: &Env, src_eid: u32, sender: &BytesN<32>) -> u64 {
|
|
164
|
+
// Return expected nonce for ordered delivery
|
|
165
|
+
// Return 0 for unordered (default)
|
|
166
|
+
Storage::max_received_nonce(env, src_eid, sender) + 1
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Custom core (version override)
|
|
172
|
+
|
|
173
|
+
```rust
|
|
174
|
+
#[oapp(custom = [core])]
|
|
175
|
+
pub struct MyOApp;
|
|
176
|
+
|
|
177
|
+
#[contract_impl(contracttrait)]
|
|
178
|
+
#[common_macros::ownable]
|
|
179
|
+
impl OAppCore for MyOApp {
|
|
180
|
+
fn oapp_version(_env: &Env) -> (u64, u64) {
|
|
181
|
+
(2, 1) // Custom version
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Multiple custom implementations
|
|
187
|
+
|
|
188
|
+
```rust
|
|
189
|
+
#[oapp(custom = [core, receiver, options_type3])]
|
|
190
|
+
pub struct MyCustomOApp;
|
|
191
|
+
|
|
192
|
+
// Implement each trait manually...
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Example: Counter OApp
|
|
196
|
+
|
|
197
|
+
See `contracts/oapps/counter/` for a complete example demonstrating:
|
|
198
|
+
|
|
199
|
+
- Basic send/receive flow
|
|
200
|
+
- Ordered nonce enforcement
|
|
201
|
+
- Compose message handling
|
|
202
|
+
- ABA (request-response) pattern
|
|
203
|
+
|
|
204
|
+
## Key traits summary
|
|
205
|
+
|
|
206
|
+
| Trait | Purpose | Default behavior |
|
|
207
|
+
| -------------------- | -------------------------------- | ------------------------------------------- |
|
|
208
|
+
| `OAppCore` | Peer management, endpoint access | Stores endpoint, manages peers |
|
|
209
|
+
| `OAppSenderInternal` | Send cross-chain messages | Handles fee payment and message dispatch |
|
|
210
|
+
| `OAppReceiver` | Receive cross-chain messages | Clears payload, delegates to `__lz_receive` |
|
|
211
|
+
| `LzReceiveInternal` | Application message handling | **Must implement** |
|
|
212
|
+
| `OAppOptionsType3` | Enforced execution options | No enforced options |
|