@layerzerolabs/oft-v2-solana-sdk 3.0.47 → 3.0.49

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 (92) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/deployments/solana-sandbox-local/{TokenOneOFT.json → 302/TokenOneOFT.json} +5 -4
  3. package/deployments/solana-sandbox-local/{TokenThreeOFT.json → 302/TokenThreeOFT.json} +5 -4
  4. package/deployments/solana-sandbox-local/{TokenTwoOFTAdapter.json → 302/TokenTwoOFTAdapter.json} +5 -4
  5. package/deployments/solana-testnet/202/TokenOneOFT.json +16 -0
  6. package/dist/index.cjs +2101 -266
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.mts +1349 -269
  9. package/dist/index.d.ts +1349 -269
  10. package/dist/index.mjs +2099 -260
  11. package/dist/index.mjs.map +1 -1
  12. package/package.json +11 -9
  13. package/src/consts.ts +5 -0
  14. package/src/generated/{accounts → oft202/accounts}/lzReceiveTypesAccounts.ts +1 -2
  15. package/src/generated/{accounts → oft202/accounts}/oFTStore.ts +1 -2
  16. package/src/generated/oft202/accounts/peerConfig.ts +178 -0
  17. package/src/generated/oft202/instructions/index.ts +18 -0
  18. package/src/generated/{instructions → oft202/instructions}/initOft.ts +1 -2
  19. package/src/generated/{instructions → oft202/instructions}/lzReceive.ts +1 -2
  20. package/src/generated/{instructions → oft202/instructions}/lzReceiveTypes.ts +1 -2
  21. package/src/generated/{instructions → oft202/instructions}/quoteOft.ts +1 -2
  22. package/src/generated/oft202/instructions/quoteSend.ts +149 -0
  23. package/src/generated/oft202/instructions/send.ts +193 -0
  24. package/src/generated/{instructions → oft202/instructions}/setOftConfig.ts +1 -2
  25. package/src/generated/{instructions → oft202/instructions}/setPause.ts +1 -2
  26. package/src/generated/{instructions → oft202/instructions}/setPeerConfig.ts +1 -2
  27. package/src/generated/{instructions → oft202/instructions}/withdrawFee.ts +1 -2
  28. package/src/generated/{programs → oft202/programs}/oft.ts +2 -2
  29. package/src/generated/oft202/types/composeParams.ts +35 -0
  30. package/src/generated/oft202/types/index.ts +22 -0
  31. package/src/generated/oft202/types/peerConfigParam.ts +143 -0
  32. package/src/generated/oft302/accounts/index.ts +11 -0
  33. package/src/generated/oft302/accounts/lzReceiveTypesAccounts.ts +167 -0
  34. package/src/generated/oft302/accounts/oFTStore.ts +198 -0
  35. package/src/generated/{accounts → oft302/accounts}/peerConfig.ts +1 -2
  36. package/src/generated/oft302/errors/index.ts +9 -0
  37. package/src/generated/oft302/errors/oft.ts +159 -0
  38. package/src/generated/oft302/index.ts +14 -0
  39. package/src/generated/oft302/instructions/initOft.ts +179 -0
  40. package/src/generated/oft302/instructions/lzReceive.ts +203 -0
  41. package/src/generated/oft302/instructions/lzReceiveTypes.ts +124 -0
  42. package/src/generated/{instructions → oft302/instructions}/oftVersion.ts +1 -2
  43. package/src/generated/oft302/instructions/quoteOft.ts +144 -0
  44. package/src/generated/{instructions → oft302/instructions}/quoteSend.ts +1 -2
  45. package/src/generated/{instructions → oft302/instructions}/send.ts +1 -2
  46. package/src/generated/oft302/instructions/setOftConfig.ts +124 -0
  47. package/src/generated/oft302/instructions/setPause.ts +119 -0
  48. package/src/generated/oft302/instructions/setPeerConfig.ts +148 -0
  49. package/src/generated/oft302/instructions/withdrawFee.ts +151 -0
  50. package/src/generated/oft302/programs/index.ts +9 -0
  51. package/src/generated/oft302/programs/oft.ts +47 -0
  52. package/src/generated/oft302/shared/index.ts +117 -0
  53. package/src/generated/oft302/types/enforcedOptions.ts +31 -0
  54. package/src/generated/oft302/types/lzAccount.ts +35 -0
  55. package/src/generated/oft302/types/lzReceiveParams.ts +50 -0
  56. package/src/generated/oft302/types/messagingFee.ts +29 -0
  57. package/src/generated/oft302/types/oFTFeeDetail.ts +34 -0
  58. package/src/generated/oft302/types/oFTLimits.ts +26 -0
  59. package/src/generated/oft302/types/oFTReceipt.ts +29 -0
  60. package/src/generated/oft302/types/oFTType.ts +23 -0
  61. package/src/generated/oft302/types/quoteOFTResult.ts +50 -0
  62. package/src/generated/oft302/types/rateLimitParams.ts +38 -0
  63. package/src/generated/oft302/types/rateLimiter.ts +38 -0
  64. package/src/generated/oft302/types/setOFTConfigParams.ts +124 -0
  65. package/src/index.ts +5 -46
  66. package/src/oft202.ts +618 -0
  67. package/src/{oft.ts → oft302.ts} +54 -55
  68. package/src/pda.ts +34 -0
  69. package/src/types.ts +40 -0
  70. package/deployments/solana-sandbox-local/TokenFourOFTAdapter.json +0 -15
  71. /package/src/generated/{accounts → oft202/accounts}/index.ts +0 -0
  72. /package/src/generated/{errors → oft202/errors}/index.ts +0 -0
  73. /package/src/generated/{errors → oft202/errors}/oft.ts +0 -0
  74. /package/src/generated/{index.ts → oft202/index.ts} +0 -0
  75. /package/src/generated/{programs → oft202/programs}/index.ts +0 -0
  76. /package/src/generated/{shared → oft202/shared}/index.ts +0 -0
  77. /package/src/generated/{types → oft202/types}/enforcedOptions.ts +0 -0
  78. /package/src/generated/{types → oft202/types}/lzAccount.ts +0 -0
  79. /package/src/generated/{types → oft202/types}/lzReceiveParams.ts +0 -0
  80. /package/src/generated/{types → oft202/types}/messagingFee.ts +0 -0
  81. /package/src/generated/{types → oft202/types}/oFTFeeDetail.ts +0 -0
  82. /package/src/generated/{types → oft202/types}/oFTLimits.ts +0 -0
  83. /package/src/generated/{types → oft202/types}/oFTReceipt.ts +0 -0
  84. /package/src/generated/{types → oft202/types}/oFTType.ts +0 -0
  85. /package/src/generated/{types → oft202/types}/quoteOFTResult.ts +0 -0
  86. /package/src/generated/{types → oft202/types}/rateLimitParams.ts +0 -0
  87. /package/src/generated/{types → oft202/types}/rateLimiter.ts +0 -0
  88. /package/src/generated/{types → oft202/types}/setOFTConfigParams.ts +0 -0
  89. /package/src/generated/{instructions → oft302/instructions}/index.ts +0 -0
  90. /package/src/generated/{types → oft302/types}/index.ts +0 -0
  91. /package/src/generated/{types → oft302/types}/peerConfigParam.ts +0 -0
  92. /package/src/generated/{types → oft302/types}/version.ts +0 -0
package/src/oft202.ts ADDED
@@ -0,0 +1,618 @@
1
+ /* eslint-disable @typescript-eslint/require-await */
2
+
3
+ // 1. init native OFT from existing mint
4
+ // 2. init adapter OFT from existing mint, optionally an existing escrow
5
+ // 3. Wire a peer
6
+ // 4. Set the DVN etc. options
7
+ import { hexlify } from '@ethersproject/bytes'
8
+ import {
9
+ Cluster,
10
+ Program,
11
+ ProgramError,
12
+ ProgramRepositoryInterface,
13
+ PublicKey,
14
+ RpcInterface,
15
+ Signer,
16
+ WrappedInstruction,
17
+ createNullRpc,
18
+ none,
19
+ publicKeyBytes,
20
+ some,
21
+ } from '@metaplex-foundation/umi'
22
+ import { createDefaultProgramRepository } from '@metaplex-foundation/umi-program-repository'
23
+ import { fromWeb3JsPublicKey, toWeb3JsInstruction, toWeb3JsPublicKey } from '@metaplex-foundation/umi-web3js-adapters'
24
+ import { TOKEN_PROGRAM_ID } from '@solana/spl-token'
25
+ import { AccountMeta, ComputeBudgetProgram, Connection } from '@solana/web3.js'
26
+
27
+ import {
28
+ EndpointPDADeriver,
29
+ EndpointProgram,
30
+ EventPDADeriver,
31
+ SimpleMessageLibProgram,
32
+ UlnProgram,
33
+ simulateTransaction,
34
+ } from '@layerzerolabs/lz-solana-sdk-v2'
35
+ import { PacketPath } from '@layerzerolabs/lz-v2-utilities'
36
+
37
+ import { OFT_DECIMALS } from './consts'
38
+ import * as OFTAccounts from './generated/oft202/accounts'
39
+ import * as errors from './generated/oft202/errors'
40
+ import * as instructions from './generated/oft202/instructions'
41
+ import * as types from './generated/oft202/types/index'
42
+ import { OftPDA } from './pda'
43
+ import {
44
+ SetOFTConfigParams,
45
+ SetPeerAddressParam,
46
+ SetPeerEnforcedOptionsParam,
47
+ SetPeerFeeBpsParam,
48
+ SetPeerIsEndpointV1Param,
49
+ SetPeerRateLimitParam,
50
+ } from './types'
51
+
52
+ export {
53
+ initSendLibrary,
54
+ initReceiveLibrary,
55
+ setSendLibrary,
56
+ setReceiveLibrary,
57
+ initConfig,
58
+ setConfig,
59
+ initOAppNonce,
60
+ getEndpointConfig,
61
+ getPeerAddress,
62
+ getDelegate,
63
+ getEnforcedOptions,
64
+ } from './oft302'
65
+
66
+ export * as accounts from './generated/oft202/accounts'
67
+ export * as instructions from './generated/oft202/instructions'
68
+ export * as programs from './generated/oft202/programs'
69
+ export * as shared from './generated/oft202/shared'
70
+ export * as types from './generated/oft202/types/index'
71
+ export * as errors from './generated/oft202/errors'
72
+
73
+ const ENDPOINT_PROGRAM_ID = fromWeb3JsPublicKey(EndpointProgram.PROGRAM_ID)
74
+ const PROGRAM_NAME = 'oft'
75
+
76
+ export function createOFTProgramRepo(oftProgram: PublicKey, rpc?: RpcInterface): ProgramRepositoryInterface {
77
+ if (rpc === undefined) {
78
+ rpc = createNullRpc()
79
+ rpc.getCluster = (): Cluster => 'custom'
80
+ }
81
+ return createDefaultProgramRepository({ rpc: rpc }, [
82
+ {
83
+ name: PROGRAM_NAME,
84
+ publicKey: oftProgram,
85
+ getErrorFromCode(code: number, cause?: Error): ProgramError | null {
86
+ return errors.getOftErrorFromCode(code, this, cause)
87
+ },
88
+ getErrorFromName(name: string, cause?: Error): ProgramError | null {
89
+ return errors.getOftErrorFromName(name, this, cause)
90
+ },
91
+ isOnCluster(): boolean {
92
+ return true
93
+ },
94
+ } satisfies Program,
95
+ ])
96
+ }
97
+
98
+ export function initOft(
99
+ accounts: { payer: Signer; admin: PublicKey; mint: PublicKey; escrow: Signer },
100
+ oftType: types.OFTType,
101
+ sharedDecimals = OFT_DECIMALS,
102
+ programs: { oft: PublicKey; endpoint?: PublicKey; token?: PublicKey }
103
+ ): WrappedInstruction {
104
+ const programsRepo = createOFTProgramRepo(programs.oft)
105
+ const deriver = new OftPDA(programsRepo.getPublicKey(PROGRAM_NAME))
106
+ const endpoint = new EndpointProgram.Endpoint(toWeb3JsPublicKey(programs.endpoint ?? ENDPOINT_PROGRAM_ID))
107
+ const { payer, admin, mint, escrow } = accounts
108
+ const [oftStore] = deriver.oftStore(escrow.publicKey)
109
+ const [lzReceiveTypes] = deriver.lzReceiveTypesAccounts(oftStore)
110
+
111
+ const txBuilder = instructions.initOft(
112
+ {
113
+ payer: payer,
114
+ programs: programsRepo,
115
+ },
116
+ {
117
+ // accounts
118
+ oftStore: oftStore,
119
+ lzReceiveTypesAccounts: lzReceiveTypes,
120
+ tokenMint: mint,
121
+ tokenEscrow: escrow,
122
+ tokenProgram: programs.token ?? fromWeb3JsPublicKey(TOKEN_PROGRAM_ID),
123
+ // params
124
+ oftType: oftType,
125
+ admin: admin,
126
+ sharedDecimals: sharedDecimals,
127
+ endpointProgram: fromWeb3JsPublicKey(endpoint.program),
128
+ }
129
+ )
130
+ const retval = txBuilder.addRemainingAccounts(
131
+ endpoint
132
+ .getRegisterOappIxAccountMetaForCPI(toWeb3JsPublicKey(payer.publicKey), toWeb3JsPublicKey(oftStore))
133
+ .map((acc) => {
134
+ return {
135
+ pubkey: fromWeb3JsPublicKey(acc.pubkey),
136
+ isSigner: acc.isSigner,
137
+ isWritable: acc.isWritable,
138
+ }
139
+ })
140
+ ).items[0]
141
+ retval.signers = [payer, escrow]
142
+ return retval
143
+ }
144
+
145
+ export function setOFTConfig(
146
+ accounts: {
147
+ oftStore: PublicKey
148
+ admin: Signer
149
+ },
150
+ params: SetOFTConfigParams,
151
+ programs: {
152
+ oft: PublicKey
153
+ endpoint?: PublicKey
154
+ }
155
+ ): WrappedInstruction {
156
+ let actualParams: types.SetOFTConfigParamsArgs
157
+ const { oftStore, admin } = accounts
158
+ const oftStoreWeb3Js = toWeb3JsPublicKey(oftStore)
159
+ const remainingAccounts: AccountMeta[] = []
160
+ if (params.__kind === 'Admin') {
161
+ if (params.admin === undefined) {
162
+ throw new Error('Admin is required')
163
+ }
164
+ actualParams = {
165
+ __kind: 'Admin',
166
+ fields: [params.admin],
167
+ }
168
+ } else if (params.__kind === 'Delegate') {
169
+ if (params.delegate === undefined) {
170
+ throw new Error('Delegate is required')
171
+ }
172
+ actualParams = {
173
+ __kind: 'Delegate',
174
+ fields: [params.delegate],
175
+ }
176
+ const endpointProgram = toWeb3JsPublicKey(programs.endpoint ?? ENDPOINT_PROGRAM_ID)
177
+ const [oAppRegistry] = new EndpointPDADeriver(endpointProgram).oappRegistry(oftStoreWeb3Js)
178
+ const [endpointEventAuthority] = new EventPDADeriver(endpointProgram).eventAuthority()
179
+ const keys = EndpointProgram.instructions.createSetDelegateInstructionAccounts(
180
+ {
181
+ oapp: oftStoreWeb3Js,
182
+ oappRegistry: oAppRegistry,
183
+ eventAuthority: endpointEventAuthority,
184
+ program: endpointProgram,
185
+ },
186
+ endpointProgram
187
+ )
188
+ for (const acc of keys) {
189
+ acc.isSigner = false
190
+ }
191
+ remainingAccounts.push(
192
+ {
193
+ pubkey: endpointProgram,
194
+ isSigner: false,
195
+ isWritable: false,
196
+ },
197
+ ...keys
198
+ )
199
+ } else if (params.__kind === 'DefaultFee') {
200
+ if (params.defaultFee === undefined) {
201
+ throw new Error('DefaultFee is required')
202
+ }
203
+ actualParams = {
204
+ __kind: 'DefaultFee',
205
+ fields: [params.defaultFee],
206
+ }
207
+ } else if (params.__kind === 'Paused') {
208
+ if (params.paused === undefined) {
209
+ throw new Error('Paused is required')
210
+ }
211
+ actualParams = {
212
+ __kind: 'Paused',
213
+ fields: [params.paused],
214
+ }
215
+ } else if (params.__kind === 'Pauser') {
216
+ actualParams = {
217
+ __kind: 'Pauser',
218
+ fields: [params.pauser ? some(params.pauser) : none()],
219
+ }
220
+ } else {
221
+ actualParams = {
222
+ __kind: 'Unpauser',
223
+ fields: [params.unpauser ? some(params.unpauser) : none()],
224
+ }
225
+ }
226
+
227
+ const txBuilder = instructions.setOftConfig(
228
+ { programs: createOFTProgramRepo(programs.oft) },
229
+ {
230
+ admin: admin,
231
+ oftStore: oftStore,
232
+ params: actualParams,
233
+ }
234
+ )
235
+ return txBuilder.addRemainingAccounts(
236
+ remainingAccounts.map((acc) => {
237
+ return {
238
+ pubkey: fromWeb3JsPublicKey(acc.pubkey),
239
+ isSigner: acc.isSigner,
240
+ isWritable: acc.isWritable,
241
+ }
242
+ })
243
+ ).items[0]
244
+ }
245
+
246
+ export function setPeerConfig(
247
+ accounts: {
248
+ admin: Signer
249
+ oftStore: PublicKey
250
+ },
251
+ param: (
252
+ | SetPeerAddressParam
253
+ | SetPeerFeeBpsParam
254
+ | SetPeerEnforcedOptionsParam
255
+ | SetPeerRateLimitParam
256
+ | SetPeerIsEndpointV1Param
257
+ ) & {
258
+ remote: number
259
+ },
260
+ oftProgramId: PublicKey | ProgramRepositoryInterface
261
+ ): WrappedInstruction {
262
+ const programsRepo = typeof oftProgramId === 'string' ? createOFTProgramRepo(oftProgramId) : oftProgramId
263
+ const { remote: remoteId } = param
264
+ if (remoteId % 30000 == 0) {
265
+ throw new Error('Invalid remote ID')
266
+ }
267
+ const { admin, oftStore } = accounts
268
+ const [peerPda] = new OftPDA(programsRepo.getPublicKey(PROGRAM_NAME)).peer(oftStore, remoteId)
269
+ let config: types.PeerConfigParamArgs
270
+ if (param.__kind === 'PeerAddress') {
271
+ if (param.peer.length !== 32) {
272
+ throw new Error('Peer must be 32 bytes (left-padded with zeroes)')
273
+ }
274
+ config = types.peerConfigParam('PeerAddress', [param.peer])
275
+ } else if (param.__kind === 'FeeBps') {
276
+ config = { __kind: 'FeeBps', fields: [some(param.feeBps)] }
277
+ } else if (param.__kind === 'EnforcedOptions') {
278
+ config = {
279
+ __kind: 'EnforcedOptions',
280
+ send: param.send,
281
+ sendAndCall: param.sendAndCall,
282
+ }
283
+ } else if (param.__kind === 'OutboundRateLimit' || param.__kind === 'InboundRateLimit') {
284
+ config = {
285
+ __kind: param.__kind,
286
+ fields: [
287
+ param.rateLimit
288
+ ? some({
289
+ refillPerSecond: some(param.rateLimit.refillPerSecond),
290
+ capacity: some(param.rateLimit.capacity),
291
+ })
292
+ : null,
293
+ ],
294
+ }
295
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
296
+ } else if (param.__kind === 'IsEndpointV1') {
297
+ config = { __kind: 'IsEndpointV1', fields: [param.isEndpointV1] }
298
+ } else {
299
+ throw new Error('Invalid peer config')
300
+ }
301
+
302
+ return instructions.setPeerConfig(
303
+ { programs: programsRepo },
304
+ {
305
+ admin: admin,
306
+ peer: peerPda,
307
+ oftStore: oftStore,
308
+ // params
309
+ remoteEid: remoteId,
310
+ config: config,
311
+ }
312
+ ).items[0]
313
+ }
314
+
315
+ // copied from oft302.ts withdrawFee
316
+ export function withdrawFee(
317
+ accounts: {
318
+ admin: Signer
319
+ mint: PublicKey
320
+ escrow: PublicKey
321
+ dest: PublicKey
322
+ },
323
+ amount: bigint,
324
+ programs: {
325
+ oft: PublicKey | ProgramRepositoryInterface
326
+ token?: PublicKey
327
+ }
328
+ ): WrappedInstruction {
329
+ const { admin, mint, escrow, dest } = accounts
330
+ const programsRepo = typeof programs.oft === 'string' ? createOFTProgramRepo(programs.oft) : programs.oft
331
+ const [oftStore] = new OftPDA(programsRepo.getPublicKey('oft')).oftStore(escrow)
332
+ return instructions.withdrawFee(
333
+ { programs: programsRepo },
334
+ {
335
+ admin: admin,
336
+ tokenEscrow: escrow,
337
+ tokenDest: dest,
338
+ tokenProgram: programs.token ?? fromWeb3JsPublicKey(TOKEN_PROGRAM_ID),
339
+ oftStore: oftStore,
340
+ tokenMint: mint,
341
+ // params
342
+ feeLd: amount,
343
+ }
344
+ ).items[0]
345
+ }
346
+
347
+ export async function send(
348
+ rpc: RpcInterface,
349
+ accounts: {
350
+ payer: Signer
351
+ tokenMint: PublicKey
352
+ tokenEscrow: PublicKey
353
+ tokenSource: PublicKey
354
+ peerAddr?: Uint8Array
355
+ },
356
+ sendParams: {
357
+ dstEid: number
358
+ to: Uint8Array
359
+ amountLd: bigint
360
+ minAmountLd: bigint
361
+ options?: Uint8Array
362
+ nativeFee: bigint
363
+ lzTokenFee?: bigint
364
+ composeParams?: {
365
+ composeGas: number | bigint
366
+ composeMsg: Uint8Array
367
+ }
368
+ },
369
+ programs: {
370
+ oft: PublicKey | ProgramRepositoryInterface
371
+ endpoint?: PublicKey // default is ENDPOINT_PROGRAM(76y77prsiCMvXMjuoZ5VRrhG5qYBrUMYTE5WgHqgjEn6)
372
+ token?: PublicKey // default is TOKEN_PROGRAM_ID(TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA)
373
+ },
374
+ remainingAccounts?: AccountMeta[]
375
+ ): Promise<WrappedInstruction> {
376
+ const { payer, tokenMint, tokenEscrow, tokenSource } = accounts
377
+ const { dstEid, to, amountLd, minAmountLd, options, composeParams, nativeFee, lzTokenFee } = sendParams
378
+ const programsRepo = typeof programs.oft === 'string' ? createOFTProgramRepo(programs.oft) : programs.oft
379
+ const oftProgramId = programsRepo.getPublicKey(PROGRAM_NAME)
380
+ const deriver = new OftPDA(oftProgramId)
381
+ const [oftStore] = deriver.oftStore(tokenEscrow)
382
+ const [peer] = deriver.peer(oftStore, dstEid)
383
+
384
+ const connection = new Connection(rpc.getEndpoint())
385
+ if (remainingAccounts === undefined || remainingAccounts.length === 0) {
386
+ const peerAddr: Uint8Array =
387
+ accounts.peerAddr ??
388
+ (await OFTAccounts.fetchPeerConfig({ rpc }, peer).then((peerInfo) => peerInfo.peerAddress))
389
+
390
+ const endpoint = new EndpointProgram.Endpoint(toWeb3JsPublicKey(programs.endpoint ?? ENDPOINT_PROGRAM_ID))
391
+ const msgLibProgram = await getSendLibraryProgram(connection, endpoint, payer.publicKey, oftStore, dstEid)
392
+ const packetPath: PacketPath = {
393
+ srcEid: 0,
394
+ dstEid,
395
+ sender: hexlify(publicKeyBytes(oftStore)),
396
+ receiver: hexlify(peerAddr),
397
+ }
398
+ remainingAccounts = await endpoint.getSendIXAccountMetaForCPI(
399
+ connection,
400
+ toWeb3JsPublicKey(payer.publicKey),
401
+ packetPath,
402
+ msgLibProgram
403
+ )
404
+ }
405
+
406
+ const [eventAuthorityPDA] = new EventPDADeriver(toWeb3JsPublicKey(oftProgramId)).eventAuthority()
407
+ const tokenProgram: PublicKey = programs.token ?? fromWeb3JsPublicKey(TOKEN_PROGRAM_ID)
408
+ const txBuilder = instructions.send(
409
+ { programs: programsRepo },
410
+ {
411
+ signer: payer,
412
+ peer: peer,
413
+ oftStore: oftStore,
414
+ tokenSource: tokenSource,
415
+ tokenEscrow: tokenEscrow,
416
+ tokenMint: tokenMint,
417
+ tokenProgram: tokenProgram,
418
+ eventAuthority: fromWeb3JsPublicKey(eventAuthorityPDA),
419
+ program: oftProgramId,
420
+ // params
421
+ dstEid: dstEid,
422
+ to: to,
423
+ amountLd,
424
+ minAmountLd,
425
+ options: options ?? new Uint8Array(),
426
+ nativeFee,
427
+ lzTokenFee: lzTokenFee ?? 0,
428
+ composeParams: composeParams ?? null,
429
+ }
430
+ )
431
+
432
+ // Get remaining accounts from msgLib(simple_msgLib or uln)
433
+ return txBuilder.addRemainingAccounts(
434
+ remainingAccounts.map((acc) => {
435
+ return {
436
+ pubkey: fromWeb3JsPublicKey(acc.pubkey),
437
+ isSigner: acc.isSigner,
438
+ isWritable: acc.isWritable,
439
+ }
440
+ })
441
+ ).items[0]
442
+ }
443
+
444
+ export async function quote(
445
+ rpc: RpcInterface,
446
+ accounts: {
447
+ payer: PublicKey
448
+ tokenMint: PublicKey
449
+ tokenEscrow: PublicKey
450
+ peerAddr?: Uint8Array
451
+ },
452
+ quoteParams: {
453
+ dstEid: number
454
+ to: Uint8Array
455
+ amountLd: bigint
456
+ minAmountLd: bigint
457
+ options?: Uint8Array
458
+ payInLzToken?: boolean
459
+ composeParams?: {
460
+ composeGas: number | bigint
461
+ composeMsg: Uint8Array
462
+ }
463
+ },
464
+ programs: {
465
+ oft: PublicKey | ProgramRepositoryInterface
466
+ endpoint?: PublicKey
467
+ },
468
+ remainingAccounts?: AccountMeta[]
469
+ ): Promise<{ nativeFee: bigint; lzTokenFee: bigint }> {
470
+ const { dstEid, to, amountLd, minAmountLd, options, payInLzToken, composeParams } = quoteParams
471
+ const { payer, tokenMint, tokenEscrow } = accounts
472
+ const programsRepo = typeof programs.oft === 'string' ? createOFTProgramRepo(programs.oft) : programs.oft
473
+ const deriver = new OftPDA(programsRepo.getPublicKey(PROGRAM_NAME))
474
+ const [oftStore] = deriver.oftStore(tokenEscrow)
475
+ const [peer] = deriver.peer(oftStore, dstEid)
476
+
477
+ const connection = new Connection(rpc.getEndpoint(), 'confirmed')
478
+ if (remainingAccounts === undefined || remainingAccounts.length === 0) {
479
+ const peerAddr: Uint8Array =
480
+ accounts.peerAddr ??
481
+ (await OFTAccounts.fetchPeerConfig({ rpc }, peer).then((peerInfo) => peerInfo.peerAddress))
482
+
483
+ const endpoint = new EndpointProgram.Endpoint(toWeb3JsPublicKey(programs.endpoint ?? ENDPOINT_PROGRAM_ID))
484
+ const messageLib = await getSendLibraryProgram(connection, endpoint, payer, oftStore, dstEid)
485
+
486
+ remainingAccounts = await endpoint.getQuoteIXAccountMetaForCPI(
487
+ connection,
488
+ toWeb3JsPublicKey(payer),
489
+ {
490
+ sender: hexlify(publicKeyBytes(oftStore)),
491
+ dstEid: dstEid,
492
+ receiver: hexlify(peerAddr),
493
+ },
494
+ messageLib
495
+ )
496
+ }
497
+
498
+ let txBuilder = instructions.quoteSend(
499
+ { programs: programsRepo },
500
+ {
501
+ oftStore: oftStore,
502
+ peer: peer,
503
+ tokenMint: tokenMint,
504
+ // params
505
+ dstEid: dstEid,
506
+ to: to,
507
+ amountLd: amountLd,
508
+ minAmountLd: minAmountLd,
509
+ options: options ?? new Uint8Array(),
510
+ payInLzToken: payInLzToken ?? false,
511
+ composeParams: composeParams ?? null,
512
+ }
513
+ )
514
+
515
+ txBuilder = txBuilder.addRemainingAccounts(
516
+ // Get remaining accounts from msgLib(simple_msgLib or uln)
517
+ remainingAccounts.map((acc) => {
518
+ return {
519
+ pubkey: fromWeb3JsPublicKey(acc.pubkey),
520
+ isSigner: acc.isSigner,
521
+ isWritable: acc.isWritable,
522
+ }
523
+ })
524
+ )
525
+ const web3Ix = toWeb3JsInstruction(txBuilder.getInstructions()[0])
526
+ const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
527
+ units: 1000000,
528
+ })
529
+ const buffer = await simulateTransaction(
530
+ connection,
531
+ [modifyComputeUnits, web3Ix],
532
+ web3Ix.programId,
533
+ toWeb3JsPublicKey(payer),
534
+ 'confirmed'
535
+ )
536
+ const fee = EndpointProgram.types.messagingFeeBeet.read(buffer, 0)
537
+ return { nativeFee: BigInt(fee.nativeFee.toString()), lzTokenFee: BigInt(fee.lzTokenFee.toString()) }
538
+ }
539
+
540
+ export async function quoteOft(
541
+ rpc: RpcInterface,
542
+ accounts: {
543
+ payer: PublicKey
544
+ tokenMint: PublicKey
545
+ tokenEscrow: PublicKey
546
+ },
547
+ quoteParams: {
548
+ dstEid: number
549
+ to: Uint8Array
550
+ amountLd: bigint
551
+ minAmountLd: bigint
552
+ options?: Uint8Array
553
+ payInLzToken?: boolean
554
+ composeMsg?: Uint8Array
555
+ },
556
+ oftProgram: PublicKey | ProgramRepositoryInterface
557
+ ): Promise<types.QuoteOFTResult> {
558
+ const { payer, tokenMint, tokenEscrow } = accounts
559
+ const { dstEid, to, amountLd, minAmountLd, options, payInLzToken, composeMsg } = quoteParams
560
+ const programsRepo = typeof oftProgram === 'string' ? createOFTProgramRepo(oftProgram) : oftProgram
561
+ const deriver = new OftPDA(programsRepo.getPublicKey(PROGRAM_NAME))
562
+ const [oftStore] = deriver.oftStore(tokenEscrow)
563
+ const [peer] = deriver.peer(oftStore, dstEid)
564
+ const ix = instructions
565
+ .quoteOft(
566
+ { programs: programsRepo },
567
+ {
568
+ oftStore: oftStore,
569
+ peer: peer,
570
+ tokenMint: tokenMint,
571
+ // params
572
+ dstEid: dstEid,
573
+ to: to,
574
+ amountLd: amountLd,
575
+ minAmountLd: minAmountLd,
576
+ options: options ?? new Uint8Array(),
577
+ payInLzToken: payInLzToken ?? false,
578
+ composeMsg: composeMsg ?? null,
579
+ }
580
+ )
581
+ .getInstructions()[0]
582
+ const web3Ix = toWeb3JsInstruction(ix)
583
+ const connection = new Connection(rpc.getEndpoint())
584
+ const returnedValues = await simulateTransaction(
585
+ connection,
586
+ [web3Ix],
587
+ web3Ix.programId,
588
+ toWeb3JsPublicKey(payer),
589
+ 'confirmed'
590
+ )
591
+ const [result] = types.getQuoteOFTResultSerializer().deserialize(returnedValues, 0)
592
+ return result
593
+ }
594
+
595
+ async function getSendLibraryProgram(
596
+ connection: Connection,
597
+ endpoint: EndpointProgram.Endpoint,
598
+ payer: PublicKey,
599
+ oftStore: PublicKey,
600
+ remoteEid: number
601
+ ): Promise<SimpleMessageLibProgram.SimpleMessageLib | UlnProgram.Uln> {
602
+ const sendLibInfo = await endpoint.getSendLibrary(connection, toWeb3JsPublicKey(oftStore), remoteEid)
603
+ if (!sendLibInfo?.programId) {
604
+ throw new Error('Send library not initialized or blocked message library')
605
+ }
606
+ const { programId: msgLibProgram } = sendLibInfo
607
+ const msgLibVersion = await endpoint.getMessageLibVersion(connection, toWeb3JsPublicKey(payer), msgLibProgram)
608
+ if (msgLibVersion?.major.toString() === '0' && msgLibVersion.minor == 0 && msgLibVersion.endpointVersion == 2) {
609
+ return new SimpleMessageLibProgram.SimpleMessageLib(msgLibProgram)
610
+ } else if (
611
+ msgLibVersion?.major.toString() === '3' &&
612
+ msgLibVersion.minor == 0 &&
613
+ msgLibVersion.endpointVersion == 2
614
+ ) {
615
+ return new UlnProgram.Uln(msgLibProgram)
616
+ }
617
+ throw new Error(`Unsupported message library version: ${JSON.stringify(msgLibVersion, null, 2)}`)
618
+ }