@layerzerolabs/lz-solana-sdk-v2 3.0.105-mpt.0 → 3.0.106-snapshots.0

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/src/receive.ts CHANGED
@@ -1,33 +1,24 @@
1
- import {
2
- AccountMeta,
3
- Commitment,
4
- Instruction,
5
- PublicKey,
6
- RpcInterface,
7
- defaultPublicKey,
8
- publicKey,
9
- } from '@metaplex-foundation/umi'
10
- import { array, publicKey as publicKeySerializer } from '@metaplex-foundation/umi/serializers'
11
- import { toWeb3JsInstruction, toWeb3JsPublicKey } from '@metaplex-foundation/umi-web3js-adapters'
1
+ import { Commitment, Instruction, PublicKey, RpcInterface, publicKey } from '@metaplex-foundation/umi'
12
2
  import invariant from 'tiny-invariant'
13
3
 
14
4
  import { arrayify } from '@layerzerolabs/lz-utilities'
15
5
  import { Packet, addressToBytes32 } from '@layerzerolabs/lz-v2-utilities'
16
6
 
17
- import { OmniAppPDA } from '.'
7
+ import { getLzComposeAccountsFromTypesV1 } from './compose-types-v1'
8
+ import { buildLzComposeExecutionPlan, getLzComposeTypesInfo } from './compose-types-v2'
18
9
  import { ComposeSentEvent } from './generated/kinobi/endpoint/events'
19
10
  import { EXECUTOR_PROGRAM_ID } from './generated/kinobi/executor/programs'
20
11
  import { getLzReceiveAccountsFromTypesV1 } from './receive-types-v1'
21
12
  import { buildLzReceiveExecutionPlan, getLzReceiveTypesInfo } from './receive-types-v2'
22
13
  import {
23
14
  LzComposeParams,
15
+ LzComposeTypesV2Accounts,
24
16
  LzReceiveParams,
25
17
  LzReceiveTypesV2Accounts,
26
18
  getLzComposeParamsSerializer,
27
- getLzReceiveAccountSerializer,
28
19
  getLzReceiveParamsSerializer,
29
20
  } from './types'
30
- import { instructionDiscriminator, simulateWeb3JsTransaction } from './utility'
21
+ import { instructionDiscriminator } from './utility'
31
22
 
32
23
  /**
33
24
  * Unified entry point for receiving a LayerZero message on Solana.
@@ -114,23 +105,20 @@ export async function lzReceive(
114
105
  }
115
106
 
116
107
  /**
117
- * Composes a LayerZero message.
118
- *
119
- * @param {Connection} connection - The Solana connection object.
120
- * @param {PublicKey} payer - The public key of the payer.
121
- * @param {ComposeSentEvent} event - The event containing the message details.
122
- * @param {Uint8Array} [extraData] - Optional extra data.
123
- * @param {Commitment | GetAccountInfoConfig} [commitmentOrConfig] - Optional commitment or configuration.
108
+ * Unified entry point for composing a LayerZero message on Solana.
109
+ * This function automatically detects the lz_compose_types version and dispatches to the correct logic.
124
110
  *
125
- * @returns {Promise<TransactionInstruction>} The transaction instruction.
111
+ * For V1: returns a single Instruction (legacy behavior).
112
+ * For V2: returns { signers, instructions } for multi-instruction atomic execution.
126
113
  */
127
114
  export async function lzCompose(
128
115
  rpc: RpcInterface,
129
116
  payer: PublicKey,
130
117
  event: ComposeSentEvent,
131
118
  extraData: Uint8Array = Uint8Array.from([0, 0]),
119
+ executorProgram: PublicKey = EXECUTOR_PROGRAM_ID,
132
120
  commitment: Commitment = 'confirmed'
133
- ): Promise<Instruction> {
121
+ ): Promise<{ instruction: Instruction; contextVersion: number } | ReturnType<typeof buildLzComposeExecutionPlan>> {
134
122
  const { to, from, guid, index, message } = event
135
123
  const params: LzComposeParams = {
136
124
  from,
@@ -144,97 +132,42 @@ export async function lzCompose(
144
132
  if (!accountInfo.exists) {
145
133
  throw new Error(`Account not found: ${to}`)
146
134
  }
147
- const programId = accountInfo.owner
148
- const accounts = await getLzComposeAccountMeta(rpc, payer, to, programId, params, commitment)
135
+ const composerProgram = accountInfo.owner
149
136
 
150
- const data = getLzComposeParamsSerializer().serialize(params)
151
- return {
152
- programId,
153
- keys: accounts,
154
- data: Buffer.concat([instructionDiscriminator('lz_compose'), data]),
137
+ // Try to detect version by calling lz_compose_types_info
138
+ let version = 1
139
+ let composeTypesAccounts: LzComposeTypesV2Accounts | undefined
140
+ try {
141
+ // V2: lz_compose_types_info returns version 2
142
+ composeTypesAccounts = await getLzComposeTypesInfo(rpc, payer, to, composerProgram, params, commitment)
143
+ version = 2
144
+ } catch (e) {
145
+ // If info call fails or version !== 2, fallback to V1
146
+ version = 1
155
147
  }
156
- }
157
148
 
158
- /**
159
- * Retrieves the accounts required for the LzCompose instruction.
160
- *
161
- * @param {Connection} connection - The Solana connection object.
162
- * @param {PublicKey} payer - The public key of the payer.
163
- * @param {PublicKey} to - The public key of the recipient.
164
- * @param {PublicKey} composerProgram - The public key of the composer program.
165
- * @param {LzComposeParams} params - The parameters for the LzCompose instruction.
166
- * @param {Commitment | GetAccountInfoConfig} [commitmentOrConfig] - Optional commitment or configuration.
167
- *
168
- * @returns {Promise<AccountMeta[]>} The list of account metadata.
169
- */
170
- export async function getLzComposeAccountMeta(
171
- rpc: RpcInterface,
172
- payer: PublicKey,
173
- to: PublicKey,
174
- composerProgram: PublicKey,
175
- params: LzComposeParams,
176
- commitment: Commitment = 'confirmed'
177
- ): Promise<AccountMeta[]> {
178
- const lzComposeTypesAccounts = await (async (): Promise<AccountMeta[]> => {
179
- const oappPDA = new OmniAppPDA(composerProgram)
180
- const [lzComposeTypesAccountsPDA] = oappPDA.lzComposeTypesAccounts(to)
181
- // const [lzComposeTypesAccountsPDA] = deriveLzComposeTypesAccountsPDA(composerProgram, to)
182
- // Get the lzReceiveTypesAccounts. Deserialize the AccountInfo.data to get the lzComposeTypesAccounts.
183
- const info = await rpc.getAccount(lzComposeTypesAccountsPDA, { commitment })
184
- const accounts = []
185
- if (info.exists) {
186
- const buffer = Buffer.from(info.data)
187
- const len = buffer.length - 8
188
- if (len % 32 !== 0) {
189
- throw new Error(
190
- `Invalid length of AccountInfo.data. The length must be a multiple of 32 plus 8.(n*32+8). Current length is ${buffer.length}`
191
- )
192
- }
193
- for (let i = 8; i < len; i += 32) {
194
- const [address] = publicKeySerializer().deserialize(buffer, i)
195
- accounts.push({
196
- pubkey: address,
197
- isSigner: false,
198
- isWritable: false,
199
- })
200
- }
149
+ if (version === 2) {
150
+ return buildLzComposeExecutionPlan(
151
+ rpc,
152
+ executorProgram,
153
+ payer,
154
+ to,
155
+ composerProgram,
156
+ params,
157
+ composeTypesAccounts,
158
+ commitment
159
+ )
160
+ } else {
161
+ // V1: return a single Instruction (legacy behavior)
162
+ const accounts = await getLzComposeAccountsFromTypesV1(rpc, payer, to, composerProgram, params, commitment)
163
+ const data = getLzComposeParamsSerializer().serialize(params)
164
+ return {
165
+ instruction: {
166
+ programId: composerProgram,
167
+ keys: accounts,
168
+ data: Buffer.concat([instructionDiscriminator('lz_compose'), data]),
169
+ },
170
+ contextVersion: 1,
201
171
  }
202
- return accounts
203
- })()
204
-
205
- const data = getLzComposeParamsSerializer().serialize(params)
206
- const lzComposeTypesIx: Instruction = {
207
- programId: composerProgram,
208
- keys: lzComposeTypesAccounts,
209
- data: Buffer.concat([instructionDiscriminator('lz_compose_types'), data]),
210
172
  }
211
-
212
- const keys = await simulateWeb3JsTransaction(
213
- rpc.getEndpoint(),
214
- [toWeb3JsInstruction(lzComposeTypesIx)],
215
- toWeb3JsPublicKey(composerProgram),
216
- toWeb3JsPublicKey(payer),
217
- array(getLzReceiveAccountSerializer()),
218
- 'confirmed'
219
- )
220
- return updateAccountFromSimulatedResp(keys, payer)
221
- }
222
-
223
- function updateAccountFromSimulatedResp(accounts: AccountMeta[], payer?: PublicKey): AccountMeta[] {
224
- return accounts.map((r) => {
225
- if (r.pubkey == defaultPublicKey() && r.isSigner) {
226
- if (!payer) throw new Error('payer is required')
227
- return {
228
- pubkey: payer,
229
- isSigner: true,
230
- isWritable: r.isWritable,
231
- } satisfies AccountMeta
232
- } else {
233
- return {
234
- pubkey: r.pubkey,
235
- isSigner: r.isSigner,
236
- isWritable: r.isWritable,
237
- } satisfies AccountMeta
238
- }
239
- })
240
173
  }
package/src/types.ts CHANGED
@@ -231,6 +231,10 @@ export interface LzReceiveTypesV2Accounts {
231
231
  accounts: PublicKey[]
232
232
  }
233
233
 
234
+ export interface LzComposeTypesV2Accounts {
235
+ accounts: PublicKey[]
236
+ }
237
+
234
238
  export type AddressLocator =
235
239
  | { __kind: 'Address'; fields: [PublicKey] }
236
240
  | { __kind: 'AltIndex'; fields: [number, number] }
@@ -243,14 +247,24 @@ export interface AccountMetaRef {
243
247
  isWritable: boolean
244
248
  }
245
249
 
246
- export type Instruction =
250
+ export type InstructionForLzReceive =
247
251
  | { __kind: 'LzReceive'; accounts: AccountMetaRef[] }
248
252
  | { __kind: 'Standard'; programId: PublicKey; accounts: AccountMetaRef[]; data: Uint8Array }
249
253
 
254
+ export type InstructionForLzCompose =
255
+ | { __kind: 'LzCompose'; accounts: AccountMetaRef[] }
256
+ | { __kind: 'Standard'; programId: PublicKey; accounts: AccountMetaRef[]; data: Uint8Array }
257
+
250
258
  export interface LzReceiveTypesV2Result {
251
259
  contextVersion: number
252
260
  alts: PublicKey[]
253
- instructions: Instruction[]
261
+ instructions: InstructionForLzReceive[]
262
+ }
263
+
264
+ export interface LzComposeTypesV2Result {
265
+ contextVersion: number
266
+ alts: PublicKey[]
267
+ instructions: InstructionForLzCompose[]
254
268
  }
255
269
 
256
270
  export function getAddressLocatorSerializer(): Serializer<AddressLocator, AddressLocator> {
@@ -278,6 +292,15 @@ export function getLzReceiveTypesV2AccountsSerializer(): Serializer<
278
292
  })
279
293
  }
280
294
 
295
+ export function getLzComposeTypesV2AccountsSerializer(): Serializer<
296
+ LzComposeTypesV2Accounts,
297
+ LzComposeTypesV2Accounts
298
+ > {
299
+ return struct<LzComposeTypesV2Accounts>([['accounts', array(publicKeySerializer())]], {
300
+ description: 'LzComposeTypesV2Accounts',
301
+ })
302
+ }
303
+
281
304
  export function getAccountMetaRefSerializer(): Serializer<AccountMetaRef, AccountMetaRef> {
282
305
  return struct<AccountMetaRef>(
283
306
  [
@@ -288,18 +311,18 @@ export function getAccountMetaRefSerializer(): Serializer<AccountMetaRef, Accoun
288
311
  )
289
312
  }
290
313
 
291
- export function getInstructionSerializer(): Serializer<Instruction, Instruction> {
292
- return dataEnum<Instruction>(
314
+ export function getInstructionForLzReceiveSerializer(): Serializer<InstructionForLzReceive, InstructionForLzReceive> {
315
+ return dataEnum<InstructionForLzReceive>(
293
316
  [
294
317
  [
295
318
  'LzReceive',
296
- struct<GetDataEnumKindContent<Instruction, 'LzReceive'>>([
319
+ struct<GetDataEnumKindContent<InstructionForLzReceive, 'LzReceive'>>([
297
320
  ['accounts', array(getAccountMetaRefSerializer())],
298
321
  ]),
299
322
  ],
300
323
  [
301
324
  'Standard',
302
- struct<GetDataEnumKindContent<Instruction, 'Standard'>>([
325
+ struct<GetDataEnumKindContent<InstructionForLzReceive, 'Standard'>>([
303
326
  ['programId', publicKeySerializer()],
304
327
  ['accounts', array(getAccountMetaRefSerializer())],
305
328
  ['data', bytes({ size: u32() })],
@@ -310,17 +333,49 @@ export function getInstructionSerializer(): Serializer<Instruction, Instruction>
310
333
  )
311
334
  }
312
335
 
336
+ export function getInstructionForLzComposeSerializer(): Serializer<InstructionForLzCompose, InstructionForLzCompose> {
337
+ return dataEnum<InstructionForLzCompose>(
338
+ [
339
+ [
340
+ 'LzCompose',
341
+ struct<GetDataEnumKindContent<InstructionForLzCompose, 'LzCompose'>>([
342
+ ['accounts', array(getAccountMetaRefSerializer())],
343
+ ]),
344
+ ],
345
+ [
346
+ 'Standard',
347
+ struct<GetDataEnumKindContent<InstructionForLzCompose, 'Standard'>>([
348
+ ['programId', publicKeySerializer()],
349
+ ['accounts', array(getAccountMetaRefSerializer())],
350
+ ['data', bytes({ size: u32() })],
351
+ ]),
352
+ ],
353
+ ],
354
+ { description: 'Instruction' }
355
+ )
356
+ }
313
357
  export function getLzReceiveTypesV2ResultSerializer(): Serializer<LzReceiveTypesV2Result, LzReceiveTypesV2Result> {
314
358
  return struct<LzReceiveTypesV2Result>(
315
359
  [
316
360
  ['contextVersion', u8()],
317
361
  ['alts', array(publicKeySerializer())],
318
- ['instructions', array(getInstructionSerializer())],
362
+ ['instructions', array(getInstructionForLzReceiveSerializer())],
319
363
  ],
320
364
  { description: 'LzReceiveTypesV2Result' }
321
365
  )
322
366
  }
323
367
 
368
+ export function getLzComposeTypesV2ResultSerializer(): Serializer<LzComposeTypesV2Result, LzComposeTypesV2Result> {
369
+ return struct<LzComposeTypesV2Result>(
370
+ [
371
+ ['contextVersion', u8()],
372
+ ['alts', array(publicKeySerializer())],
373
+ ['instructions', array(getInstructionForLzComposeSerializer())],
374
+ ],
375
+ { description: 'LzComposeTypesV2Result' }
376
+ )
377
+ }
378
+
324
379
  // Data Enum Helpers.
325
380
  export function addressLocator(kind: 'Payer'): GetDataEnumKind<AddressLocator, 'Payer'>
326
381