@layerzerolabs/oapp-solana-contracts 1.2.63 → 1.2.65

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.
@@ -1,74 +1,46 @@
1
+ //! Receive plan format (planner version 3) and Endpoint account helpers for building plans.
2
+ //!
3
+ //! See `docs/lz-receive-types.md` for the planning protocol.
1
4
  use crate::{
2
- common::{AccountMetaRef, AddressLocator},
3
- COMPOSED_MESSAGE_HASH_SEED, ENDPOINT_SEED, EVENT_SEED, NONCE_SEED, OAPP_SEED,
4
- PAYLOAD_HASH_SEED,
5
+ COMPOSED_MESSAGE_HASH_SEED, ENDPOINT_SEED, EVENT_SEED, NONCE_SEED, OAPP_SEED, PAYLOAD_HASH_SEED,
5
6
  };
6
7
  use anchor_lang::{prelude::*, solana_program::system_program::ID as SYSTEM_ID};
7
8
  use solana_keccak_hasher::hash;
8
9
 
9
- /// Version identifier returned by `lz_receive_types_info` for the V2 flow.
10
- pub const LZ_RECEIVE_TYPES_VERSION: u8 = 2;
10
+ /// Planner version returned by `lz_receive_types_info`.
11
+ pub const LZ_RECEIVE_TYPES_VERSION: u8 = 3;
11
12
 
12
- /// Payload returned from `lz_receive_types_info` when the version is V2.
13
+ /// Returned by `lz_receive_types_info`: the planner's read-only, app-specific inputs.
13
14
  ///
14
- /// The executor uses these accounts to construct the follow-up
15
- /// `lz_receive_types_v2` call.
15
+ /// The client prepends the payer and the plan scratch account. Account order is part of the
16
+ /// planner ABI, including Anchor's optional-account sentinels.
16
17
  #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
17
- pub struct LzReceiveTypesV2Accounts {
18
+ pub struct LzReceiveTypesV3Accounts {
18
19
  pub accounts: Vec<Pubkey>,
19
20
  }
20
21
 
21
- /// Output of the lz_receive_types_v2 instruction.
22
- ///
23
- /// This structure enables the multi-instruction execution model where OApps can
24
- /// define multiple instructions to be executed atomically by the Executor.
25
- /// The Executor constructs a single transaction containing all returned instructions.
26
- #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
27
- pub struct LzReceiveTypesV2Result {
28
- /// The version of context account
22
+ use crate::common::{AccountMetaRef, AddressLocator};
23
+
24
+ /// Receive plan written by `lz_receive_types_v3`.
25
+ #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug, PartialEq, Eq)]
26
+ pub struct LzReceiveTypesV3Result {
27
+ /// Execution-context version; selects the account [`AddressLocator::Context`] resolves to.
29
28
  pub context_version: u8,
30
- /// ALTs required for this execution context
31
- /// Used by the Executor to resolve AltIndex references in AccountMetaRef
32
- /// Enables efficient account list compression for complex transactions
33
- pub alts: Vec<Pubkey>,
34
- /// The complete list of instructions required for LzReceive execution
35
- /// MUST include exactly one LzReceive instruction
36
- /// MAY include additional Standard instructions for preprocessing/postprocessing
37
- /// Instructions are executed in the order returned
29
+ /// Executed in order in one transaction. Must contain exactly one `LzReceive`; `Standard`
30
+ /// instructions may precede or follow it.
38
31
  pub instructions: Vec<Instruction>,
39
32
  }
40
33
 
41
- /// The list of instructions that can be executed in the LzReceive transaction.
42
- ///
43
- /// V2's multi-instruction model enables complex patterns such as:
44
- /// - Preprocessing steps before lz_receive (e.g., account initialization)
45
- /// - Postprocessing steps after lz_receive (e.g., verification, cleanup)
46
- /// - ABA messaging patterns with additional LayerZero sends
47
- /// - Conditional execution flows based on message content
48
- #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
34
+ /// One instruction of a receive plan.
35
+ #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug, PartialEq, Eq)]
49
36
  pub enum Instruction {
50
- /// The main LzReceive instruction (exactly one required per transaction)
51
- /// This instruction processes the incoming cross-chain message
52
- LzReceive {
53
- /// Account list for the lz_receive instruction
54
- /// Uses AddressLocator for flexible address resolution
55
- accounts: Vec<AccountMetaRef>,
56
- },
57
- /// Arbitrary custom instruction for preprocessing/postprocessing
58
- /// Enables OApps to implement complex execution flows
59
- Standard {
60
- /// Target program ID for the custom instruction
61
- program_id: Pubkey,
62
- /// Account list for the custom instruction
63
- /// Uses same AddressLocator system as LzReceive
64
- accounts: Vec<AccountMetaRef>,
65
- /// Instruction data payload
66
- /// Raw bytes containing the instruction's parameters
67
- data: Vec<u8>,
68
- },
37
+ /// The delivery: this program's `lz_receive`, called with the original params.
38
+ LzReceive { accounts: Vec<AccountMetaRef> },
39
+ /// Any other instruction, submitted as given.
40
+ Standard { program_id: Pubkey, accounts: Vec<AccountMetaRef>, data: Vec<u8> },
69
41
  }
70
42
 
71
- /// V2 version of get_accounts_for_clear that returns AccountMetaRef
43
+ /// Accounts for the Endpoint `clear` CPI, in the order [`crate::endpoint_cpi::clear`] expects.
72
44
  pub fn get_accounts_for_clear(
73
45
  endpoint_program: Pubkey,
74
46
  receiver: &Pubkey,
@@ -111,7 +83,8 @@ pub fn get_accounts_for_clear(
111
83
  ]
112
84
  }
113
85
 
114
- /// V2 version of get_accounts_for_send_compose that returns AccountMetaRef
86
+ /// Accounts for the Endpoint `send_compose` CPI, in the order [`crate::endpoint_cpi::send_compose`]
87
+ /// expects. The Executor's payer funds the composed-message account.
115
88
  pub fn get_accounts_for_send_compose(
116
89
  endpoint_program: Pubkey,
117
90
  from: &Pubkey,
package/src/oapp_info.rs CHANGED
@@ -32,7 +32,7 @@ pub const OAPP_BASE_SCHEMA_VERSION: u8 = 1;
32
32
 
33
33
  /// IDL version (instructions + events) for this build. See `docs/oapp-info.md` § `idl_version`
34
34
  /// Bump Rules.
35
- pub const OAPP_BASE_IDL_VERSION: IdlVersion = IdlVersion { major: 1, minor: 0 };
35
+ pub const OAPP_BASE_IDL_VERSION: IdlVersion = IdlVersion { major: 2, minor: 0 };
36
36
 
37
37
  /// Sentinel: no app-layer TLV entry follows `OAppBase`.
38
38
  pub const NO_APP_DISCRIMINATOR: [u8; 8] = [0u8; 8];
package/src/options.rs CHANGED
@@ -55,15 +55,11 @@ mod tests {
55
55
  }
56
56
 
57
57
  #[test]
58
- fn assert_type_3_empty_returns_invalid_length() {
59
- let err = assert_type_3(&[]).unwrap_err();
60
- assert_eq!(err, OAppError::InvalidOptionsLength.into());
61
- }
62
-
63
- #[test]
64
- fn assert_type_3_one_byte_returns_invalid_length() {
65
- let err = assert_type_3(&[0x00]).unwrap_err();
66
- assert_eq!(err, OAppError::InvalidOptionsLength.into());
58
+ fn assert_type_3_rejects_options_shorter_than_the_type_header() {
59
+ for options in [&[][..], &[0x00][..]] {
60
+ let err = assert_type_3(options).unwrap_err();
61
+ assert_eq!(err, OAppError::InvalidOptionsLength.into());
62
+ }
67
63
  }
68
64
 
69
65
  #[test]
@@ -82,12 +78,6 @@ mod tests {
82
78
  assert_eq!(result, vec![0x01, 0x02, 0x03]);
83
79
  }
84
80
 
85
- #[test]
86
- fn combine_no_enforced_extra_also_empty_returns_empty() {
87
- let result = combine_options(vec![], &[]).unwrap();
88
- assert_eq!(result, Vec::<u8>::new());
89
- }
90
-
91
81
  // -----------------------------------------------------------------------
92
82
  // combine_options — extra empty
93
83
  // -----------------------------------------------------------------------
package/src/types.rs CHANGED
@@ -112,3 +112,47 @@ pub struct IsComposeMsgSenderParams {
112
112
  /// The account claiming authorization to send the compose message.
113
113
  pub compose_sender: Pubkey,
114
114
  }
115
+
116
+ /// Params for the OApp `clear` instruction (messaging-channel manager).
117
+ ///
118
+ /// `receiver` is intentionally omitted — the handler injects the OApp PDA.
119
+ #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
120
+ pub struct ClearParams {
121
+ pub src_eid: u32,
122
+ pub sender: [u8; 32],
123
+ pub nonce: u64,
124
+ pub guid: [u8; 32],
125
+ pub message: Vec<u8>,
126
+ }
127
+
128
+ /// Params for the OApp `skip` instruction (messaging-channel manager).
129
+ ///
130
+ /// `receiver` is intentionally omitted — the handler injects the OApp PDA.
131
+ #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
132
+ pub struct SkipParams {
133
+ pub src_eid: u32,
134
+ pub sender: [u8; 32],
135
+ pub nonce: u64,
136
+ }
137
+
138
+ /// Params for the OApp `burn` instruction (messaging-channel manager).
139
+ ///
140
+ /// `receiver` is intentionally omitted — the handler injects the OApp PDA.
141
+ #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
142
+ pub struct BurnParams {
143
+ pub src_eid: u32,
144
+ pub sender: [u8; 32],
145
+ pub nonce: u64,
146
+ pub payload_hash: [u8; 32],
147
+ }
148
+
149
+ /// Params for the OApp `nilify` instruction (message nilifier).
150
+ ///
151
+ /// `receiver` is intentionally omitted — the handler injects the OApp PDA.
152
+ #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
153
+ pub struct NilifyParams {
154
+ pub src_eid: u32,
155
+ pub sender: [u8; 32],
156
+ pub nonce: u64,
157
+ pub payload_hash: [u8; 32],
158
+ }
@@ -1,17 +0,0 @@
1
- //! Code generator for the `lz_compose_types_v2` instruction.
2
- //!
3
- //! This instruction has no default implementation — users MUST provide
4
- //! a custom handler named `lz_compose_types_v2` with `#[composer_instruction]`.
5
-
6
- use super::ComposerCodegenContext;
7
- use anchor_trait::InstructionSpec;
8
- use quote::quote;
9
-
10
- pub(super) fn spec() -> InstructionSpec<ComposerCodegenContext> {
11
- InstructionSpec {
12
- params_type: Some(quote!(::oapp::types::LzComposeParams)),
13
- return_type: quote!(::oapp::lz_compose_types_v2::LzComposeTypesV2Result),
14
- is_view: true,
15
- default_impl: None,
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- //! Code generator for the `lz_receive_types_v2` instruction.
2
- //!
3
- //! This instruction has no default implementation — users MUST provide
4
- //! a custom handler named `lz_receive_types_v2` with `#[oapp_instruction]`.
5
-
6
- use super::CodegenContext;
7
- use anchor_trait::InstructionSpec;
8
- use quote::quote;
9
-
10
- pub(super) fn spec() -> InstructionSpec<CodegenContext> {
11
- InstructionSpec {
12
- params_type: Some(quote!(::oapp::types::LzReceiveParams)),
13
- return_type: quote!(::oapp::lz_receive_types_v2::LzReceiveTypesV2Result),
14
- is_view: true,
15
- default_impl: None,
16
- }
17
- }
@@ -1,88 +0,0 @@
1
- use crate::{common::AccountMetaRef, COMPOSED_MESSAGE_HASH_SEED, EVENT_SEED};
2
- use anchor_lang::prelude::*;
3
- use solana_keccak_hasher::hash;
4
-
5
- /// Version identifier returned by `lz_compose_types_info` for the V2 flow.
6
- pub const LZ_COMPOSE_TYPES_VERSION: u8 = 2;
7
-
8
- /// Payload returned from `lz_compose_types_info` when the version is V2.
9
- ///
10
- /// The executor uses these accounts to construct the follow-up
11
- /// `lz_compose_types_v2` call.
12
- #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
13
- pub struct LzComposeTypesV2Accounts {
14
- pub accounts: Vec<Pubkey>,
15
- }
16
-
17
- /// Output of the lz_compose_types_v2 instruction.
18
- ///
19
- /// This structure enables the multi-instruction execution model where composers
20
- /// can define multiple instructions to be executed atomically by the Executor.
21
- /// The Executor constructs a single transaction containing all returned instructions.
22
- #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
23
- pub struct LzComposeTypesV2Result {
24
- /// The version of context account
25
- pub context_version: u8,
26
- /// ALTs required for this execution context
27
- /// Used by the Executor to resolve AltIndex references in AccountMetaRef
28
- pub alts: Vec<Pubkey>,
29
- /// The complete list of instructions required for LzCompose execution
30
- /// MUST include exactly one LzCompose instruction
31
- /// MAY include additional Standard instructions for preprocessing/postprocessing
32
- /// Instructions are executed in the order returned
33
- pub instructions: Vec<ComposeInstruction>,
34
- }
35
-
36
- /// The list of instructions that can be executed in the LzCompose transaction.
37
- #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
38
- pub enum ComposeInstruction {
39
- /// The main LzCompose instruction (exactly one required per transaction)
40
- /// This instruction processes the incoming composed message
41
- LzCompose {
42
- /// Account list for the lz_compose instruction
43
- /// Uses AddressLocator for flexible address resolution
44
- accounts: Vec<AccountMetaRef>,
45
- },
46
- /// Arbitrary custom instruction for preprocessing/postprocessing
47
- Standard {
48
- /// Target program ID for the custom instruction
49
- program_id: Pubkey,
50
- /// Account list for the custom instruction
51
- accounts: Vec<AccountMetaRef>,
52
- /// Instruction data payload
53
- data: Vec<u8>,
54
- },
55
- }
56
-
57
- /// V2 version of get_accounts_for_clear_compose that returns AccountMetaRef
58
- pub fn get_accounts_for_clear_compose(
59
- endpoint_program: Pubkey,
60
- from: &Pubkey,
61
- to: &Pubkey,
62
- guid: &[u8; 32],
63
- index: u16,
64
- composed_message: &[u8],
65
- ) -> Vec<AccountMetaRef> {
66
- let (composed_message_account, _) = Pubkey::find_program_address(
67
- &[
68
- COMPOSED_MESSAGE_HASH_SEED,
69
- &from.to_bytes(),
70
- &to.to_bytes(),
71
- &guid[..],
72
- &index.to_be_bytes(),
73
- &hash(composed_message).to_bytes(),
74
- ],
75
- &endpoint_program,
76
- );
77
-
78
- let (event_authority_account, _) =
79
- Pubkey::find_program_address(&[EVENT_SEED], &endpoint_program);
80
-
81
- vec![
82
- AccountMetaRef { pubkey: endpoint_program.into(), is_writable: false },
83
- AccountMetaRef { pubkey: (*to).into(), is_writable: false },
84
- AccountMetaRef { pubkey: composed_message_account.into(), is_writable: true },
85
- AccountMetaRef { pubkey: event_authority_account.into(), is_writable: false },
86
- AccountMetaRef { pubkey: endpoint_program.into(), is_writable: false },
87
- ]
88
- }