@layerzerolabs/protocol-stellar-v2 0.2.122 → 0.2.124

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.
Files changed (34) hide show
  1. package/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +7 -1
  2. package/endpoint-v2/src/tests/endpoint_v2/quote.rs +2 -2
  3. package/endpoint-v2/src/tests/endpoint_v2/ttl_config.rs +4 -1
  4. package/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +0 -1
  5. package/endpoint-v2/src/tests/message_lib_manager/require_receive_lib_for_eid.rs +9 -3
  6. package/endpoint-v2/src/tests/message_lib_manager/require_send_lib_for_eid.rs +6 -2
  7. package/endpoint-v2/src/tests/message_lib_manager/require_supported_eid.rs +6 -2
  8. package/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +1 -4
  9. package/endpoint-v2/src/tests/messaging_channel/inbound.rs +1 -4
  10. package/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -1
  11. package/endpoint-v2/src/tests/messaging_channel/nilify.rs +3 -12
  12. package/endpoint-v2/src/tests/messaging_channel/pending_inbound_nonces.rs +0 -1
  13. package/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +1 -0
  14. package/message-libs/uln-302/src/tests/send_uln302/send.rs +20 -4
  15. package/message-libs/uln-302/src/tests/uln302/get_app_receive_uln_config.rs +2 -2
  16. package/package.json +8 -8
  17. package/rustfmt.toml +8 -11
  18. package/upgrader/src/tests/mod.rs +1 -1
  19. package/workers/dvn/src/tests/auth.rs +12 -60
  20. package/workers/executor/src/auth.rs +3 -8
  21. package/workers/executor/src/storage.rs +1 -1
  22. package/workers/executor/src/tests/auth.rs +6 -1
  23. package/workers/executor/src/tests/executor.rs +5 -5
  24. package/workers/executor/src/tests/setup.rs +1 -2
  25. package/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +5 -5
  26. package/workers/executor-fee-lib/src/tests/executor_option.rs +2 -2
  27. package/workers/executor-helper/src/executor_helper.rs +0 -1
  28. package/workers/executor-helper/src/tests/executor_helper.rs +0 -1
  29. package/workers/price-feed/src/tests/price_feed.rs +11 -11
  30. package/workers/worker/src/tests/worker.rs +27 -27
  31. package/docs/error-spec.md +0 -55
  32. package/docs/layerzero-v2-on-stellar.md +0 -511
  33. package/docs/oapp-guide.md +0 -5
  34. package/docs/oft-guide.md +0 -5
@@ -1,511 +0,0 @@
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**: `apps/oapp-app/contracts/stellar/`
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**: `apps/oft-app/contracts/stellar/oft-core/` (core traits) and `apps/oft-app/contracts/stellar/oft/`
143
- (token types and extensions)
144
-
145
- **Key traits**:
146
-
147
- | Trait | Purpose |
148
- | ------------- | ----------------------------------------------------- |
149
- | `OFTCore` | Public interface: `send()`, `quote_send()`, `token()` |
150
- | `OFTInternal` | Internal implementation: `__debit()`, `__credit()` |
151
-
152
- **Features**:
153
-
154
- - Token type flexibility (LockUnlock or MintBurn)
155
- - Fee extension for outbound transfers
156
- - Pausable extension
157
- - Rate limiter extension
158
- - Dust removal and slippage protection
159
-
160
- ## Messaging flow
161
-
162
- ### Sending a message
163
-
164
- ```mermaid
165
- sequenceDiagram
166
- participant OApp
167
- participant Endpoint as EndpointV2
168
- participant SendLib as SendLib (ULN302)
169
- participant DVN
170
- participant Executor
171
-
172
- OApp->>Endpoint: quote(params)
173
- Endpoint-->>OApp: MessagingFee
174
-
175
- OApp->>Endpoint: send(params, refund_address)
176
- Note over Endpoint: Increment outbound nonce
177
- Note over Endpoint: Create GUID = keccak256(nonce, src_eid, sender, dst_eid, receiver)
178
-
179
- Endpoint->>SendLib: send(packet, options)
180
- SendLib->>DVN: assignJob(packet_header, payload_hash, confirmations)
181
- SendLib->>Executor: assignJob(packet_header, payload_hash, options)
182
- Note over SendLib: Calculate Treasury fee
183
- SendLib-->>Endpoint: (fee recipients, fees)
184
-
185
- Note over Endpoint: Distribute fees to workers
186
- Endpoint-->>OApp: MessagingReceipt
187
- Note over Endpoint: Emit PacketSent event
188
- ```
189
-
190
- ### Receiving a message
191
-
192
- ```mermaid
193
- sequenceDiagram
194
- participant DVN
195
- participant ReceiveLib as ReceiveLib (ULN302)
196
- participant Endpoint as EndpointV2
197
- participant Executor
198
- participant OApp
199
-
200
- rect rgb(240, 248, 255)
201
- Note over DVN, ReceiveLib: Step 1a: DVN Attestation
202
- Note over DVN: Monitor source chain for PacketSent
203
- Note over DVN: Wait for block confirmations
204
- DVN->>ReceiveLib: verify(dvn, packet_header, payload_hash, confirmations)
205
- Note over ReceiveLib: Record DVN attestation
206
- Note over ReceiveLib: (repeat for each DVN in quorum)
207
-
208
- Note over ReceiveLib, Endpoint: Step 1b: Commit (permissionless)
209
- ReceiveLib->>ReceiveLib: commit_verification(packet_header, payload_hash)
210
- Note over ReceiveLib: Check if quorum reached
211
- ReceiveLib->>Endpoint: verify(origin, receiver, payload_hash)
212
- Note over Endpoint: Store payload_hash
213
- Note over Endpoint: Emit PacketVerified event
214
- end
215
-
216
- rect rgb(240, 255, 240)
217
- Note over Executor, OApp: Step 2: Execution
218
- Executor->>OApp: lz_receive(origin, guid, message, extra_data)
219
- OApp->>Endpoint: clear(origin, guid, message)
220
- Note over Endpoint: Validate payload against stored hash
221
- Note over Endpoint: Emit PacketDelivered event
222
- Endpoint-->>OApp: (success)
223
- Note over OApp: Execute __lz_receive() logic
224
- end
225
- ```
226
-
227
- ## Stellar-specific considerations
228
-
229
- Several differences between Soroban and EVM require protocol-level adaptations:
230
-
231
- 1. Stellar's variable-length address model differs from LayerZero's fixed
232
- bytes32 address abstraction
233
- 2. Soroban's Time-To-Live (TTL)-based storage model requires active state
234
- maintenance, unlike EVM's persistent storage
235
- 3. Soroban's 200-read-per-transaction storage limit makes the lazy inbound
236
- nonce model susceptible to denial-of-service for certain OApps
237
- 4. Soroban prohibits reentrancy, requiring alternative patterns for cross-contract
238
- call flows
239
-
240
- ### Constraint 1: bytes32 address format mismatch
241
-
242
- LayerZero V2 standardizes all cross-chain addresses using bytes32. Stellar uses
243
- StrKey-encoded addresses of different types:
244
-
245
- | Address Type | Structure | Usage |
246
- | ------------ | ------------------------------------------------------ | ------------------------ |
247
- | G-Address | 1-byte version + 32-byte public key + 2-byte checksum | EOAs (Ed25519 key pairs) |
248
- | C-Address | 1-byte version + 32-byte contract ID + 2-byte checksum | Soroban smart contracts |
249
- | M-Address | G-address payload + 64-bit ID (exceeds 32 bytes) | Exchange sub-accounts |
250
-
251
- **Key observation**: G-Address and C-Address share the same 32-byte payload
252
- structure, and the payload alone is guaranteed to be unique across both types.
253
-
254
- **Solution: Deterministic address resolution**
255
-
256
- All bytes32-encoded addresses are resolved at execution time:
257
-
258
- 1. **OApp & Composer addresses**: The bytes32 value is interpreted directly as a
259
- Soroban contract ID and converted to a C-address.
260
-
261
- 2. **Native drop & OFT receiver addresses**: Contract-first detection is
262
- applied:
263
- - Convert the bytes32 payload to a C-address
264
- - If a contract exists at that address, treat as C-address
265
- - Otherwise, treat as G-address
266
-
267
- This resolution is deterministic and safe. Soroban guarantees that a deployed
268
- contract address cannot correspond to a valid G-address private key, eliminating
269
- ambiguity.
270
-
271
- ### Constraint 2: TTL-based storage model
272
-
273
- All contract data entries on Soroban have a TTL. When TTL expires, data becomes
274
- archived and inaccessible (but always restorable).
275
-
276
- **Challenges**:
277
-
278
- - **Cost impact**: The Endpoint contract (~60 KB) costs ~3.0 USD/month to keep
279
- alive. Restoration after archival (~4 months bump) costs ~12 USD.
280
- - **Execution variability**: TTL extension during `lzReceive` introduces
281
- additional fees and risk of out-of-gas failures.
282
- - **OApp-induced operations**: OApps (e.g., SAC tokens) may perform their own
283
- TTL bumps, adding unpredictable overhead.
284
-
285
- **Solution: Hybrid TTL extension strategy**
286
-
287
- LayerZero adopts a hybrid approach combining Self-Extension with Client
288
- Extension:
289
-
290
- 1. **Self-Extension (default)**: Contracts automatically extend TTL for storage
291
- entries when accessed if remaining TTL falls below a configured threshold.
292
- This is autonomous and requires no external maintenance.
293
-
294
- 2. **Client Extension (selective)**: For low-activity periods, off-chain
295
- services or sealer-assisted extension can keep critical components (Endpoint,
296
- ULN) alive without imposing costs on users.
297
-
298
- **Configurable TTL parameters**: Unlike typical Soroban apps that hardcode TTL
299
- values, LayerZero exposes TTL thresholds and extension targets as configurable
300
- values. This follows Stellar team recommendations, as storage fees and network
301
- constraints may evolve.
302
-
303
- **Governance safeguards**:
304
-
305
- - Hard upper cap on extension targets (e.g., 1 year) to prevent excessive fees
306
- - TTL parameters can be permanently frozen once the ecosystem stabilizes
307
-
308
- ### Constraint 3: Storage read limits
309
-
310
- Soroban enforces a hard limit of 200 persistent/temporary storage reads per
311
- transaction. Under the lazy inbound nonce model used in EVM, the `inbound_nonce`
312
- is not stored directly — it is computed on the fly by iterating forward from the
313
- last checkpoint (`lazy_inbound_nonce`) and probing storage for each consecutive
314
- payload hash. The same iterative check occurs during `clear`, which must verify
315
- that all nonces between the checkpoint and the target nonce have been verified.
316
-
317
- For certain OApps, failed `lz_receive` executions can create nonce gaps that
318
- grow over time. Under the lazy model, clearing subsequent messages requires
319
- iterating across these gaps, and the accumulated storage reads can exceed the
320
- 200-read limit, making the messaging path susceptible to denial-of-service.
321
-
322
- **Solution: Eager inbound nonce with pending nonce list (Solana model)**
323
-
324
- Stellar adopts the same inbound nonce model used by LayerZero V2 on Solana.
325
- Instead of lazily computing the inbound nonce via storage probing, the
326
- `inbound_nonce` is stored directly and updated eagerly during verification:
327
-
328
- 1. **`PendingInboundNonces`**: A sorted list of out-of-order verified nonces is
329
- maintained in a single storage entry per path. When a message is verified
330
- (or skipped/nilified), its nonce is inserted into this list.
331
-
332
- 2. **Drain on insert**: After each insertion, consecutive nonces at the front of
333
- the list are drained to advance the `inbound_nonce`. For example, if
334
- `inbound_nonce = 3` and the pending list becomes `[4, 5, 7]`, nonces 4 and 5
335
- are drained, advancing `inbound_nonce` to 5.
336
-
337
- 3. **O(1) clear**: The `clear_payload` operation becomes a simple comparison
338
- (`nonce <= inbound_nonce`) with no iteration or storage probing.
339
-
340
- 4. **Bounded list size**: The pending list is capped at 256 entries
341
- (`PENDING_INBOUND_NONCE_MAX_LEN`). Nonces beyond `inbound_nonce + 256`
342
- cannot be verified, preventing unbounded memory growth and limiting the
343
- maximum storage reads per verify operation.
344
-
345
- This eliminates the iterative storage reads that could cause DoS under the lazy
346
- model, keeping all operations within Soroban's transaction resource limits.
347
-
348
- ### Constraint 4: Reentrancy prohibition
349
-
350
- Soroban prohibits reentrancy—a contract cannot call itself, directly or
351
- indirectly, within the same transaction. This fundamental difference from EVM
352
- requires rethinking several LayerZero patterns.
353
-
354
- #### Impact on DVN design
355
-
356
- On EVM, the DVN contract uses a **self-call pattern** for multisig-authorized
357
- self-configuration (e.g., setting destination configs, updating signers). An
358
- admin submits M-of-N signatures over a set of calls to the DVN. The DVN verifies
359
- the signatures, then calls itself to execute the configuration changes. For
360
- external calls like `ULN302.verify()`, the DVN simply calls the target contract
361
- directly after signature verification.
362
-
363
- ```
364
- EVM DVN Flow (self-configuration):
365
- ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
366
- │ Admin │───►│ DVN │───►│ DVN │ (self-call after
367
- │ │ │ (verify) │ │ (execute) │ sig verification)
368
- └─────────────┘ └─────────────┘ └─────────────┘
369
-
370
- EVM DVN Flow (external calls):
371
- ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
372
- │ Admin │───►│ DVN │───►│ ULN302 │ (direct call after
373
- │ │ │ (verify) │ │ .verify() │ sig verification)
374
- └─────────────┘ └─────────────┘ └─────────────┘
375
- ```
376
-
377
- The self-call pattern for configuration fails on Soroban because the DVN cannot
378
- call itself. The solution is to implement DVN as an **Abstract Account** (custom
379
- account). Soroban's custom account interface allows contracts to define
380
- authorization logic via `__check_auth`. The DVN's `__check_auth` only authorizes
381
- **self-calls** (calls targeting the DVN contract itself). For self-configuration,
382
- the multisig quorum directly authorizes calls to the DVN's own functions (e.g.,
383
- `set_admin`, `set_signer`). For external calls like `ULN302.verify()`, the DVN
384
- exposes an `execute_transaction(calls)` function that is itself a self-call
385
- validated by `__check_auth`, then dispatches each call to the target contract:
386
-
387
- ```
388
- Stellar DVN Flow (self-configuration via Abstract Account):
389
- ┌─────────────┐ ┌─────────────┐
390
- │ Admin │───►│ DVN │ __check_auth validates multisig
391
- │ (submits │ │ .set_admin()│ for the self-call
392
- │ tx with │ │ │
393
- │ DVN auth) │ │ │
394
- └─────────────┘ └─────────────┘
395
-
396
- Stellar DVN Flow (external calls via execute_transaction):
397
- ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
398
- │ Admin │───►│ DVN │───►│ ULN302 │
399
- │ (submits │ │ .execute_ │ │ .verify() │
400
- │ tx with │ │ transaction│ │ │
401
- │ DVN auth) │ │ (__check_ │ │ │
402
- │ │ │ auth) │ │ │
403
- └─────────────┘ └─────────────┘ └─────────────┘
404
- ```
405
-
406
- The DVN's `__check_auth` validates:
407
-
408
- - Verifier ID (VID) matches
409
- - Authorization hasn't expired
410
- - Admin signature is valid (Ed25519) — except for `set_admin` calls
411
- - Call data hash hasn't been replayed
412
- - M-of-N secp256k1 signatures from the quorum
413
-
414
- #### Impact on executor design
415
-
416
- LayerZero supports a common cross-chain pattern called **ABA messaging**—an
417
- OApp on chain B receives a message from chain A and atomically sends a response
418
- back to chain A within the same transaction:
419
-
420
- ```
421
- ABA Pattern:
422
- Chain A Chain B
423
- ┌───────┐ ┌───────┐
424
- │ OApp │ ──── msg1 ─────► │ OApp │
425
- │ │ ◄─── msg2 ───── │ │ (msg2 sent in lz_receive handler)
426
- └───────┘ └───────┘
427
- ```
428
-
429
- If the executor were a regular contract that calls the OApp, it would be locked
430
- during the receive flow. When the OApp attempts to send a message back (which
431
- requires interacting with the executor for fee quoting), the transaction would
432
- fail due to reentrancy:
433
-
434
- ```
435
- ❌ Regular Contract Executor (fails ABA):
436
- ┌──────────┐ ┌───────┐ ┌──────────┐ ┌─────────────┐
437
- │ Executor │───►│ OApp │───►│ Endpoint │───►│ Executor │ BLOCKED!
438
- │ .call() │ │ │ │ .send() │ │.assign_job()| (reentrancy)
439
- └──────────┘ └───────┘ └──────────┘ └─────────────┘
440
- ```
441
-
442
- By implementing executor as an **Abstract Account**, the executor doesn't
443
- "call" the OApp—it authorizes the OApp's `lz_receive` invocation. The executor
444
- contract remains accessible for the send flow:
445
-
446
- ```
447
- ✓ Abstract Account Executor (supports ABA):
448
- ┌───────┐ ┌──────────┐
449
- │ OApp │ ◄───────── executor auth ──────────── │ Executor │ (not in call stack,
450
- │ │ via __check_auth │ AA │ remains accessible)
451
- │ │ ─► Endpoint.send() ─► .assign_job() ─► │ │ ✓ Works!
452
- └───────┘ └──────────┘
453
- ```
454
-
455
- #### Impact on message delivery design
456
-
457
- The same reentrancy constraint affects how messages are delivered to OApps.
458
-
459
- **EVM approach (push mode)**: The endpoint is the entry point. After verifying
460
- and clearing the payload, the endpoint calls the OApp's `lzReceive`:
461
-
462
- ```
463
- EVM Push Mode:
464
- Executor ──► Endpoint.lzReceive() ──► OApp.lzReceive()
465
-
466
- └── (clear payload, then call OApp)
467
- ```
468
-
469
- This fails on Soroban for ABA messaging. If the endpoint calls the OApp, the
470
- endpoint is locked. When the OApp tries to send a response message, it cannot
471
- call back into the endpoint:
472
-
473
- ```
474
- ❌ Push Mode on Stellar (fails ABA):
475
- Executor ──► Endpoint.lz_receive() ──► OApp ──► Endpoint.send() BLOCKED!
476
- (reentrancy)
477
- ```
478
-
479
- **Stellar approach (pull mode)**: The OApp is the entry point. The executor
480
- authorizes the OApp's `lz_receive` call, and the OApp pulls verification from
481
- the endpoint by calling `clear`:
482
-
483
- ```
484
- ✓ Pull Mode on Stellar (supports ABA):
485
- Executor auth ──► OApp.lz_receive() ──► Endpoint.clear()
486
-
487
- └──► Endpoint.send() ✓ Works!
488
- (endpoint not in call stack)
489
- ```
490
-
491
- **Summary of reentrancy adaptations**:
492
-
493
- | Component | EVM Pattern | Stellar Pattern | Reason |
494
- | --------- | -------------------------------- | ------------------------------------ | ------------------- |
495
- | DVN | Self-call after sig verification | Abstract Account with `__check_auth` | Cannot self-call |
496
- | Executor | Regular contract calls OApp | Abstract Account authorizes OApp | ABA pattern support |
497
- | Delivery | Push (Endpoint → OApp) | Pull (OApp → Endpoint.clear) | ABA pattern support |
498
-
499
- ## Building OApps and OFTs
500
-
501
- - [OApp guide](../../../../../apps/oapp-app/contracts/stellar/docs/oapp-guide.md) —
502
- Building Omnichain Applications using the OApp framework, macros, and traits
503
- (stub: [oapp-guide.md](oapp-guide.md))
504
- - [OFT guide](../../../../../apps/oft-app/contracts/stellar/docs/oft-guide.md) —
505
- Building Omnichain Fungible Tokens with MintBurn/LockUnlock strategies and extensions
506
- (stub: [oft-guide.md](oft-guide.md))
507
-
508
- ## Error codes
509
-
510
- See [error-spec.md](error-spec.md) for the error code allocation strategy and
511
- detailed specifications.
@@ -1,5 +0,0 @@
1
- # Building OApps on Stellar
2
-
3
- This guide moved with the OApp package out of the protocol workspace.
4
-
5
- See **[apps/oapp-app/contracts/stellar/docs/oapp-guide.md](../../../../../apps/oapp-app/contracts/stellar/docs/oapp-guide.md)**.
package/docs/oft-guide.md DELETED
@@ -1,5 +0,0 @@
1
- # Building OFTs on Stellar
2
-
3
- This guide moved with the OFT packages out of the protocol workspace.
4
-
5
- See **[apps/oft-app/contracts/stellar/docs/oft-guide.md](../../../../../apps/oft-app/contracts/stellar/docs/oft-guide.md)**.