@chainlink/ccip-sdk 0.90.2 → 0.91.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.
Files changed (202) hide show
  1. package/README.md +35 -26
  2. package/dist/aptos/exec.d.ts +4 -5
  3. package/dist/aptos/exec.d.ts.map +1 -1
  4. package/dist/aptos/exec.js +5 -14
  5. package/dist/aptos/exec.js.map +1 -1
  6. package/dist/aptos/hasher.d.ts +18 -0
  7. package/dist/aptos/hasher.d.ts.map +1 -1
  8. package/dist/aptos/hasher.js +18 -0
  9. package/dist/aptos/hasher.js.map +1 -1
  10. package/dist/aptos/index.d.ts +127 -28
  11. package/dist/aptos/index.d.ts.map +1 -1
  12. package/dist/aptos/index.js +199 -70
  13. package/dist/aptos/index.js.map +1 -1
  14. package/dist/aptos/logs.d.ts +18 -0
  15. package/dist/aptos/logs.d.ts.map +1 -1
  16. package/dist/aptos/logs.js +21 -3
  17. package/dist/aptos/logs.js.map +1 -1
  18. package/dist/aptos/send.d.ts +22 -5
  19. package/dist/aptos/send.d.ts.map +1 -1
  20. package/dist/aptos/send.js +23 -15
  21. package/dist/aptos/send.js.map +1 -1
  22. package/dist/aptos/token.d.ts +6 -0
  23. package/dist/aptos/token.d.ts.map +1 -1
  24. package/dist/aptos/token.js +6 -0
  25. package/dist/aptos/token.js.map +1 -1
  26. package/dist/aptos/types.d.ts +16 -1
  27. package/dist/aptos/types.d.ts.map +1 -1
  28. package/dist/aptos/types.js +13 -0
  29. package/dist/aptos/types.js.map +1 -1
  30. package/dist/aptos/utils.d.ts +1 -1
  31. package/dist/aptos/utils.js +1 -1
  32. package/dist/chain.d.ts +185 -99
  33. package/dist/chain.d.ts.map +1 -1
  34. package/dist/chain.js +38 -15
  35. package/dist/chain.js.map +1 -1
  36. package/dist/commits.d.ts +4 -10
  37. package/dist/commits.d.ts.map +1 -1
  38. package/dist/commits.js +2 -1
  39. package/dist/commits.js.map +1 -1
  40. package/dist/evm/const.d.ts +5 -0
  41. package/dist/evm/const.d.ts.map +1 -1
  42. package/dist/evm/const.js +5 -0
  43. package/dist/evm/const.js.map +1 -1
  44. package/dist/evm/errors.d.ts +5 -0
  45. package/dist/evm/errors.d.ts.map +1 -1
  46. package/dist/evm/errors.js +6 -1
  47. package/dist/evm/errors.js.map +1 -1
  48. package/dist/evm/hasher.d.ts +16 -2
  49. package/dist/evm/hasher.d.ts.map +1 -1
  50. package/dist/evm/hasher.js +17 -3
  51. package/dist/evm/hasher.js.map +1 -1
  52. package/dist/evm/index.d.ts +176 -31
  53. package/dist/evm/index.d.ts.map +1 -1
  54. package/dist/evm/index.js +312 -154
  55. package/dist/evm/index.js.map +1 -1
  56. package/dist/evm/logs.d.ts +20 -0
  57. package/dist/evm/logs.d.ts.map +1 -0
  58. package/dist/evm/logs.js +194 -0
  59. package/dist/evm/logs.js.map +1 -0
  60. package/dist/evm/messages.d.ts +11 -2
  61. package/dist/evm/messages.d.ts.map +1 -1
  62. package/dist/evm/messages.js +4 -2
  63. package/dist/evm/messages.js.map +1 -1
  64. package/dist/evm/offchain.d.ts +7 -2
  65. package/dist/evm/offchain.d.ts.map +1 -1
  66. package/dist/evm/offchain.js +12 -7
  67. package/dist/evm/offchain.js.map +1 -1
  68. package/dist/execution.d.ts +19 -62
  69. package/dist/execution.d.ts.map +1 -1
  70. package/dist/execution.js +28 -31
  71. package/dist/execution.js.map +1 -1
  72. package/dist/extra-args.d.ts +35 -5
  73. package/dist/extra-args.d.ts.map +1 -1
  74. package/dist/extra-args.js +10 -5
  75. package/dist/extra-args.js.map +1 -1
  76. package/dist/gas.d.ts +6 -8
  77. package/dist/gas.d.ts.map +1 -1
  78. package/dist/gas.js +7 -9
  79. package/dist/gas.js.map +1 -1
  80. package/dist/hasher/common.d.ts +3 -2
  81. package/dist/hasher/common.d.ts.map +1 -1
  82. package/dist/hasher/common.js +2 -2
  83. package/dist/hasher/common.js.map +1 -1
  84. package/dist/hasher/hasher.d.ts +8 -2
  85. package/dist/hasher/hasher.d.ts.map +1 -1
  86. package/dist/hasher/hasher.js +8 -3
  87. package/dist/hasher/hasher.js.map +1 -1
  88. package/dist/hasher/merklemulti.d.ts +11 -9
  89. package/dist/hasher/merklemulti.d.ts.map +1 -1
  90. package/dist/hasher/merklemulti.js +17 -16
  91. package/dist/hasher/merklemulti.js.map +1 -1
  92. package/dist/index.d.ts +16 -8
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +17 -7
  95. package/dist/index.js.map +1 -1
  96. package/dist/requests.d.ts +39 -25
  97. package/dist/requests.d.ts.map +1 -1
  98. package/dist/requests.js +42 -35
  99. package/dist/requests.js.map +1 -1
  100. package/dist/selectors.d.ts +1 -1
  101. package/dist/solana/cleanup.d.ts +14 -10
  102. package/dist/solana/cleanup.d.ts.map +1 -1
  103. package/dist/solana/cleanup.js +35 -33
  104. package/dist/solana/cleanup.js.map +1 -1
  105. package/dist/solana/exec.d.ts +19 -11
  106. package/dist/solana/exec.d.ts.map +1 -1
  107. package/dist/solana/exec.js +86 -163
  108. package/dist/solana/exec.js.map +1 -1
  109. package/dist/solana/hasher.d.ts +7 -2
  110. package/dist/solana/hasher.d.ts.map +1 -1
  111. package/dist/solana/hasher.js +7 -2
  112. package/dist/solana/hasher.js.map +1 -1
  113. package/dist/solana/index.d.ts +202 -84
  114. package/dist/solana/index.d.ts.map +1 -1
  115. package/dist/solana/index.js +367 -252
  116. package/dist/solana/index.js.map +1 -1
  117. package/dist/solana/offchain.d.ts +8 -18
  118. package/dist/solana/offchain.d.ts.map +1 -1
  119. package/dist/solana/offchain.js +29 -83
  120. package/dist/solana/offchain.js.map +1 -1
  121. package/dist/solana/patchBorsh.d.ts +5 -1
  122. package/dist/solana/patchBorsh.d.ts.map +1 -1
  123. package/dist/solana/patchBorsh.js +57 -46
  124. package/dist/solana/patchBorsh.js.map +1 -1
  125. package/dist/solana/send.d.ts +28 -10
  126. package/dist/solana/send.d.ts.map +1 -1
  127. package/dist/solana/send.js +44 -77
  128. package/dist/solana/send.js.map +1 -1
  129. package/dist/solana/types.d.ts +22 -1
  130. package/dist/solana/types.d.ts.map +1 -1
  131. package/dist/solana/types.js +12 -1
  132. package/dist/solana/types.js.map +1 -1
  133. package/dist/solana/utils.d.ts +58 -4
  134. package/dist/solana/utils.d.ts.map +1 -1
  135. package/dist/solana/utils.js +110 -7
  136. package/dist/solana/utils.js.map +1 -1
  137. package/dist/sui/hasher.d.ts +18 -0
  138. package/dist/sui/hasher.d.ts.map +1 -1
  139. package/dist/sui/hasher.js +18 -0
  140. package/dist/sui/hasher.js.map +1 -1
  141. package/dist/sui/index.d.ts +99 -12
  142. package/dist/sui/index.d.ts.map +1 -1
  143. package/dist/sui/index.js +108 -19
  144. package/dist/sui/index.js.map +1 -1
  145. package/dist/sui/types.d.ts +6 -0
  146. package/dist/sui/types.d.ts.map +1 -1
  147. package/dist/sui/types.js +5 -0
  148. package/dist/sui/types.js.map +1 -1
  149. package/dist/supported-chains.d.ts +2 -1
  150. package/dist/supported-chains.d.ts.map +1 -1
  151. package/dist/supported-chains.js.map +1 -1
  152. package/dist/types.d.ts +127 -16
  153. package/dist/types.d.ts.map +1 -1
  154. package/dist/types.js +18 -0
  155. package/dist/types.js.map +1 -1
  156. package/dist/utils.d.ts +67 -46
  157. package/dist/utils.d.ts.map +1 -1
  158. package/dist/utils.js +143 -21
  159. package/dist/utils.js.map +1 -1
  160. package/package.json +13 -9
  161. package/src/aptos/exec.ts +7 -18
  162. package/src/aptos/hasher.ts +18 -0
  163. package/src/aptos/index.ts +288 -110
  164. package/src/aptos/logs.ts +21 -3
  165. package/src/aptos/send.ts +25 -22
  166. package/src/aptos/token.ts +6 -0
  167. package/src/aptos/types.ts +26 -2
  168. package/src/aptos/utils.ts +1 -1
  169. package/src/chain.ts +243 -108
  170. package/src/commits.ts +6 -7
  171. package/src/evm/const.ts +5 -0
  172. package/src/evm/errors.ts +6 -1
  173. package/src/evm/hasher.ts +20 -4
  174. package/src/evm/index.ts +416 -214
  175. package/src/evm/logs.ts +255 -0
  176. package/src/evm/messages.ts +11 -5
  177. package/src/evm/offchain.ts +13 -4
  178. package/src/execution.ts +40 -32
  179. package/src/extra-args.ts +38 -6
  180. package/src/gas.ts +7 -9
  181. package/src/hasher/common.ts +3 -2
  182. package/src/hasher/hasher.ts +12 -4
  183. package/src/hasher/merklemulti.ts +17 -16
  184. package/src/index.ts +29 -23
  185. package/src/requests.ts +64 -46
  186. package/src/selectors.ts +1 -1
  187. package/src/solana/cleanup.ts +49 -34
  188. package/src/solana/exec.ts +128 -272
  189. package/src/solana/hasher.ts +13 -4
  190. package/src/solana/index.ts +483 -356
  191. package/src/solana/offchain.ts +32 -102
  192. package/src/solana/patchBorsh.ts +65 -50
  193. package/src/solana/send.ts +52 -111
  194. package/src/solana/types.ts +44 -3
  195. package/src/solana/utils.ts +143 -19
  196. package/src/sui/hasher.ts +18 -0
  197. package/src/sui/index.ts +143 -31
  198. package/src/sui/types.ts +6 -0
  199. package/src/supported-chains.ts +2 -1
  200. package/src/types.ts +130 -18
  201. package/src/utils.ts +168 -26
  202. package/tsconfig.json +2 -1
@@ -1,119 +1,52 @@
1
- import { type AnchorProvider, type IdlTypes, Program } from '@coral-xyz/anchor'
1
+ import { Buffer } from 'buffer'
2
+
3
+ import { type IdlTypes, Program } from '@coral-xyz/anchor'
2
4
  import {
3
5
  type AccountMeta,
4
- type Transaction,
6
+ type Connection,
5
7
  type TransactionInstruction,
6
8
  AddressLookupTableAccount,
7
9
  AddressLookupTableProgram,
8
- ComputeBudgetProgram,
9
10
  PublicKey,
10
- SendTransactionError,
11
11
  SystemProgram,
12
- TransactionExpiredBlockheightExceededError,
13
- TransactionMessage,
14
- VersionedTransaction,
15
12
  } from '@solana/web3.js'
16
13
  import BN from 'bn.js'
17
14
  import { hexlify } from 'ethers'
18
15
 
19
- import type { ExecutionReport } from '../types.ts'
16
+ import { type ExecutionReport, type WithLogger, ChainFamily } from '../types.ts'
20
17
  import { IDL as CCIP_OFFRAMP_IDL } from './idl/1.6.0/CCIP_OFFRAMP.ts'
21
18
  import { encodeSolanaOffchainTokenData } from './offchain.ts'
22
- import type { CCIPMessage_V1_6_Solana } from './types.ts'
23
- import type { ChainTransaction } from '../chain.ts'
24
- import { getDataBytes, sleep, toLeArray } from '../utils.ts'
25
- import { bytesToBuffer, simulateTransaction, simulationProvider } from './utils.ts'
26
- import './patchBorsh.ts'
27
-
28
- type ExecStepTx = readonly [reason: string, transactions: VersionedTransaction]
19
+ import type { CCIPMessage_V1_6_Solana, UnsignedSolanaTx } from './types.ts'
20
+ import { getDataBytes, toLeArray } from '../utils.ts'
21
+ import { bytesToBuffer } from './utils.ts'
29
22
 
30
23
  type ExecAlt = {
31
- addressLookupTableAccount: AddressLookupTableAccount
32
- initialTxs: ExecStepTx[]
33
- finalTxs: ExecStepTx[]
34
- }
35
-
36
- export async function executeReport({
37
- offrampProgram,
38
- execReport,
39
- ...opts
40
- }: {
41
- offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
42
- execReport: ExecutionReport<CCIPMessage_V1_6_Solana>
43
- gasLimit?: number
44
- forceLookupTable?: boolean
45
- forceBuffer?: boolean
46
- clearLeftoverAccounts?: boolean
47
- }): Promise<Pick<ChainTransaction, 'hash'>> {
48
- const provider = offrampProgram.provider as AnchorProvider
49
- const wallet = provider.wallet
50
- const connection = provider.connection
51
-
52
- const execTxs = await buildExecTxToSolana(offrampProgram, execReport, opts?.gasLimit, opts)
53
-
54
- let execTxSignature: string, signature: string
55
- for (const [i, [reason, transaction]] of execTxs.entries()) {
56
- // Refresh the blockhash for each transaction, as the blockhash is only valid for a short time
57
- // and we spend a lot of time waiting for finalization of the previous transactions.
58
- transaction.message.recentBlockhash = (await connection.getLatestBlockhash()).blockhash
59
-
60
- const signed = await wallet.signTransaction(transaction)
61
-
62
- try {
63
- signature = await connection.sendTransaction(signed)
64
-
65
- if (reason === 'exec') execTxSignature = signature
66
- } catch (e) {
67
- if (
68
- e instanceof SendTransactionError &&
69
- e.logs?.some((log) =>
70
- log.includes('Error Code: ExecutionReportBufferAlreadyContainsChunk.'),
71
- )
72
- ) {
73
- console.warn(
74
- `Skipping tx ${i + 1} of ${execTxs.length} because a chunk is already in the buffer.`,
75
- )
76
- continue
77
- } else {
78
- throw e
79
- }
80
- }
81
-
82
- console.debug(`Confirming tx #${i + 1} of ${execTxs.length}: ${signature} (${reason})...`)
83
- for (let currentAttempt = 0; ; currentAttempt++) {
84
- try {
85
- const latestBlockhash = await connection.getLatestBlockhash()
86
- await connection.confirmTransaction(
87
- {
88
- signature,
89
- blockhash: latestBlockhash.blockhash,
90
- lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
91
- },
92
- 'confirmed',
93
- )
94
- break
95
- } catch (e) {
96
- if (currentAttempt < 5 && e instanceof TransactionExpiredBlockheightExceededError) {
97
- await sleep(1000)
98
- } else {
99
- throw e
100
- }
101
- }
102
- }
103
- }
104
-
105
- return { hash: execTxSignature! }
24
+ initialIxs: TransactionInstruction[]
25
+ lookupTable: AddressLookupTableAccount
26
+ finalIxs: TransactionInstruction[]
106
27
  }
107
28
 
108
- async function buildExecTxToSolana(
109
- offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>,
29
+ /**
30
+ * Generate unsigned tx to execute a CCIP report on Solana.
31
+ * @param ctx - Context containing connection and logger
32
+ * @param payer - Payer of the transaction.
33
+ * @param offramp - Address of the OffRamp contract.
34
+ * @param execReport - Execution report.
35
+ * @param opts - Options for txs to be generated
36
+ * - forceBuffer - Sends report in chunks for buffering in offRamp before execution
37
+ * - forceLookupTable - Creates lookup table for execution transaction, and deactivates in the end
38
+ * - clearLeftoverAccounts - Resets buffer before filling it in
39
+ * @returns Transaction hash of the execution.
40
+ */
41
+ export async function generateUnsignedExecuteReport(
42
+ ctx: { connection: Connection } & WithLogger,
43
+ payer: PublicKey,
44
+ offramp: PublicKey,
110
45
  execReport: ExecutionReport<CCIPMessage_V1_6_Solana>,
111
- computeUnitsOverride: number | undefined,
112
46
  opts?: { forceLookupTable?: boolean; forceBuffer?: boolean; clearLeftoverAccounts?: boolean },
113
- ): Promise<ExecStepTx[]> {
114
- const provider = offrampProgram.provider as AnchorProvider
115
- offrampProgram = new Program(CCIP_OFFRAMP_IDL, offrampProgram.programId, provider)
116
- const payerAddress = provider.wallet.publicKey
47
+ ): Promise<UnsignedSolanaTx> {
48
+ const { connection, logger = console } = ctx
49
+ const program = new Program(CCIP_OFFRAMP_IDL, offramp, ctx)
117
50
 
118
51
  let bufferId
119
52
  if (opts?.forceBuffer) {
@@ -127,15 +60,16 @@ async function buildExecTxToSolana(
127
60
  accounts,
128
61
  addressLookupTables,
129
62
  } = await getManuallyExecuteInputs({
63
+ payer,
64
+ offramp: program,
130
65
  execReport,
131
- offrampProgram,
132
- transmitter: payerAddress.toBase58(),
133
66
  bufferId,
67
+ logger,
134
68
  })
135
69
 
136
70
  const addressLookupTableAccounts = await Promise.all(
137
71
  addressLookupTables.map(async (acc) => {
138
- const lookupTableAccountInfo = await provider.connection.getAddressLookupTable(acc)
72
+ const lookupTableAccountInfo = await connection.getAddressLookupTable(acc)
139
73
 
140
74
  if (!lookupTableAccountInfo.value) {
141
75
  throw new Error(`Lookup table account not found: ${acc.toBase58()}`)
@@ -145,35 +79,30 @@ async function buildExecTxToSolana(
145
79
  }),
146
80
  )
147
81
 
148
- let serializedReport = offrampProgram.coder.types.encode(
149
- 'ExecutionReportSingleChain',
150
- preparedReport,
151
- )
152
-
153
- const { blockhash: recentBlockhash } = await provider.connection.getLatestBlockhash()
82
+ let serializedReport = program.coder.types.encode('ExecutionReportSingleChain', preparedReport)
154
83
 
155
84
  let alt
156
85
  if (opts?.forceLookupTable) {
157
- alt = await buildLookupTableTxs(provider, accounts)
158
- addressLookupTableAccounts.push(alt.addressLookupTableAccount)
86
+ alt = await buildLookupTableIxs(
87
+ ctx,
88
+ payer,
89
+ accounts.map((acc) => acc.pubkey),
90
+ )
91
+ addressLookupTableAccounts.push(alt.lookupTable)
159
92
  }
160
93
 
161
- const transactions: ExecStepTx[] = []
94
+ const instructions: TransactionInstruction[] = []
162
95
  if (bufferId) {
163
- console.log(`Execute report will be pre-buffered through the offramp. This may take some time.`)
164
- transactions.push(
165
- ...(await bufferedTransactionData(
166
- offrampProgram,
167
- serializedReport,
168
- recentBlockhash,
169
- bufferId,
170
- opts,
171
- )),
172
- )
96
+ logger.info(`Execute report will be pre-buffered through the offramp. This may take some time.`)
97
+ const bufferingIxs = await bufferedTransactionData(payer, program, serializedReport, bufferId, {
98
+ logger,
99
+ ...opts,
100
+ })
101
+ instructions.push(...bufferingIxs)
173
102
  serializedReport = Buffer.from([]) // clear 1st param to manuallyExecute method if buffered
174
103
  }
175
104
 
176
- const execTx = await offrampProgram.methods
105
+ const execIx = await program.methods
177
106
  .manuallyExecute(serializedReport, tokenIndexes)
178
107
  .accounts({
179
108
  config: accounts[0].pubkey,
@@ -190,61 +119,40 @@ async function buildExecTxToSolana(
190
119
  rmnRemoteConfig: accounts[11].pubkey,
191
120
  })
192
121
  .remainingAccounts(accounts.slice(12))
193
- .transaction()
194
-
195
- computeUnitsOverride ||= Math.ceil(
196
- 1.1 *
197
- ((
198
- await simulateTransaction({
199
- instructions: execTx.instructions,
200
- connection: provider.connection,
201
- payerKey: provider.wallet.publicKey,
202
- addressLookupTableAccounts,
203
- computeUnitsOverride,
204
- })
205
- ).unitsConsumed || 0),
206
- )
207
-
208
- // Add compute budget instruction at the beginning of instructions
209
- execTx.instructions.unshift(
210
- ComputeBudgetProgram.setComputeUnitLimit({
211
- units: computeUnitsOverride,
212
- }),
213
- )
122
+ .instruction()
214
123
 
215
124
  // actual exec tx
216
- transactions.push([
217
- 'exec',
218
- toVersionedTransaction(
219
- execTx.instructions,
220
- provider.wallet.publicKey,
221
- recentBlockhash,
222
- addressLookupTableAccounts,
223
- ),
224
- ])
125
+ let execIndex = instructions.length
126
+ instructions.push(execIx)
225
127
 
128
+ // "sandwich" instructions with ALT create+extend, then deactivate
226
129
  if (alt) {
227
- transactions.unshift(...alt.initialTxs)
228
- transactions.push(...alt.finalTxs)
130
+ instructions.unshift(...alt.initialIxs)
131
+ execIndex += alt.initialIxs.length
132
+ instructions.push(...alt.finalIxs)
229
133
  }
230
134
 
231
- return transactions
135
+ return {
136
+ family: ChainFamily.Solana,
137
+ instructions,
138
+ lookupTables: addressLookupTableAccounts,
139
+ mainIndex: execIndex,
140
+ }
232
141
  }
233
142
 
234
- async function buildLookupTableTxs(
235
- provider: AnchorProvider,
236
- accounts: readonly AccountMeta[],
143
+ async function buildLookupTableIxs(
144
+ { connection, logger = console }: { connection: Connection } & WithLogger,
145
+ authority: PublicKey,
146
+ addresses: PublicKey[],
237
147
  ): Promise<ExecAlt> {
238
- const recentSlot = await provider.connection.getSlot('finalized')
148
+ const recentSlot = await connection.getSlot('confirmed')
239
149
 
240
150
  const [createIx, altAddr] = AddressLookupTableProgram.createLookupTable({
241
- authority: provider.wallet.publicKey,
242
- payer: provider.wallet.publicKey,
151
+ authority,
152
+ payer: authority,
243
153
  recentSlot,
244
154
  })
245
- console.log('Using Address Lookup Table', altAddr.toBase58())
246
-
247
- const addresses = accounts.map((a) => a.pubkey)
155
+ logger.info('Using Address Lookup Table', altAddr.toBase58())
248
156
 
249
157
  if (addresses.length > 256) {
250
158
  throw new Error(
@@ -257,7 +165,6 @@ async function buildLookupTableTxs(
257
165
  const firstChunkLength = 28
258
166
  const maxAddressesPerTx = 35
259
167
  const extendIxs: TransactionInstruction[] = []
260
- const ranges: [number, number][] = []
261
168
  for (
262
169
  let [start, end] = [0, firstChunkLength];
263
170
  start < addresses.length;
@@ -265,18 +172,17 @@ async function buildLookupTableTxs(
265
172
  ) {
266
173
  const addressesChunk = addresses.slice(start, end)
267
174
  const extendIx = AddressLookupTableProgram.extendLookupTable({
268
- payer: provider.wallet.publicKey,
269
- authority: provider.wallet.publicKey,
175
+ authority,
176
+ payer: authority,
270
177
  lookupTable: altAddr,
271
178
  addresses: addressesChunk,
272
179
  })
273
180
  extendIxs.push(extendIx)
274
- ranges.push([start, start + addressesChunk.length - 1])
275
181
  }
276
182
 
277
183
  const deactivateIx = AddressLookupTableProgram.deactivateLookupTable({
278
184
  lookupTable: altAddr,
279
- authority: provider.wallet.publicKey,
185
+ authority,
280
186
  })
281
187
 
282
188
  // disable closeTx, to be cleaned in SolanaChain.cleanUpBuffers
@@ -286,87 +192,59 @@ async function buildLookupTableTxs(
286
192
  // lookupTable: altAddr,
287
193
  // })
288
194
 
289
- const { blockhash: recentBlockhash } = await provider.connection.getLatestBlockhash()
290
-
291
195
  return {
292
- addressLookupTableAccount: new AddressLookupTableAccount({
196
+ lookupTable: new AddressLookupTableAccount({
293
197
  key: altAddr,
294
198
  state: {
295
- deactivationSlot: BigInt(0),
199
+ deactivationSlot: 2n ** 64n - 1n,
296
200
  lastExtendedSlot: recentSlot,
297
201
  lastExtendedSlotStartIndex: 0,
298
202
  addresses,
299
203
  },
300
204
  }),
301
- initialTxs: [
302
- // first extendIx fits in create tx
303
- [
304
- `lookup[create + 0..${ranges[0][1]}]`,
305
- toVersionedTransaction(
306
- [createIx, extendIxs[0]],
307
- provider.wallet.publicKey,
308
- recentBlockhash,
309
- ),
310
- ],
311
- ...extendIxs
312
- .slice(1)
313
- .map<ExecStepTx>((ix, i) => [
314
- `lookup[${ranges[i + 1][0]}..${ranges[i + 1][1]}]`,
315
- toVersionedTransaction([ix], provider.wallet.publicKey, recentBlockhash),
316
- ]),
317
- ],
318
- finalTxs: [
319
- [
320
- `lookup[deactivate]`,
321
- toVersionedTransaction([deactivateIx], provider.wallet.publicKey, recentBlockhash),
322
- ],
323
- ],
205
+ initialIxs: [createIx, ...extendIxs],
206
+ finalIxs: [deactivateIx],
324
207
  }
325
208
  }
326
209
 
327
210
  async function bufferedTransactionData(
328
- offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>,
211
+ payer: PublicKey,
212
+ offramp: Program<typeof CCIP_OFFRAMP_IDL>,
329
213
  serializedReport: Buffer,
330
- recentBlockhash: string,
331
214
  bufferId: Buffer,
332
- opts?: { clearLeftoverAccounts?: boolean },
333
- ): Promise<ExecStepTx[]> {
334
- const provider = offrampProgram.provider as AnchorProvider
335
-
215
+ {
216
+ logger = console,
217
+ clearLeftoverAccounts,
218
+ }: { clearLeftoverAccounts?: boolean } & WithLogger = {},
219
+ ): Promise<TransactionInstruction[]> {
336
220
  const [bufferAddress] = PublicKey.findProgramAddressSync(
337
- [Buffer.from('execution_report_buffer'), bufferId, provider.wallet.publicKey.toBuffer()],
338
- offrampProgram.programId,
221
+ [Buffer.from('execution_report_buffer'), bufferId, payer.toBuffer()],
222
+ offramp.programId,
339
223
  )
340
224
 
341
- const [configPDA] = PublicKey.findProgramAddressSync(
342
- [Buffer.from('config')],
343
- offrampProgram.programId,
344
- )
225
+ const [configPDA] = PublicKey.findProgramAddressSync([Buffer.from('config')], offramp.programId)
345
226
 
346
- console.log(
227
+ logger.info(
347
228
  `The bufferID is ${hexlify(bufferId)}, and the PDA address for the buffer is ${bufferAddress.toString()}\nIf this buffering process is aborted, remember to cleanUp the account to recover locked rent.`,
348
229
  )
349
230
 
350
231
  const chunkSize = 800
351
- const bufferedExecTxs: ExecStepTx[] = []
232
+ const bufferedExecIxs: TransactionInstruction[] = []
352
233
 
353
234
  const bufferingAccounts = {
354
235
  executionReportBuffer: bufferAddress,
355
236
  config: configPDA,
356
- authority: provider.wallet.publicKey,
237
+ authority: payer,
357
238
  systemProgram: SystemProgram.programId,
358
239
  }
359
240
 
360
- if (opts?.clearLeftoverAccounts) {
361
- const clearTx = await offrampProgram.methods
362
- .closeExecutionReportBuffer(bufferId)
363
- .accounts(bufferingAccounts)
364
- .transaction()
365
-
366
- bufferedExecTxs.push([
367
- 'buffering[clear]',
368
- toVersionedTransaction(clearTx, provider.wallet.publicKey, recentBlockhash),
369
- ])
241
+ if (clearLeftoverAccounts) {
242
+ bufferedExecIxs.push(
243
+ await offramp.methods
244
+ .closeExecutionReportBuffer(bufferId)
245
+ .accounts(bufferingAccounts)
246
+ .instruction(),
247
+ )
370
248
  }
371
249
 
372
250
  const numChunks = Math.ceil(serializedReport.length / chunkSize)
@@ -374,42 +252,29 @@ async function bufferedTransactionData(
374
252
  const end = Math.min(i + chunkSize, serializedReport.length)
375
253
  const chunk: Buffer = serializedReport.subarray(i, end)
376
254
 
377
- const appendTx = await offrampProgram.methods
378
- .bufferExecutionReport(bufferId, serializedReport.length, chunk, i / chunkSize, numChunks)
379
- .accounts(bufferingAccounts)
380
- .transaction()
381
- bufferedExecTxs.push([
382
- `buffering[${i / chunkSize}=${end - i}B]`,
383
- toVersionedTransaction(appendTx, provider.wallet.publicKey, recentBlockhash),
384
- ])
255
+ bufferedExecIxs.push(
256
+ await offramp.methods
257
+ .bufferExecutionReport(bufferId, serializedReport.length, chunk, i / chunkSize, numChunks)
258
+ .accounts(bufferingAccounts)
259
+ .instruction(),
260
+ )
385
261
  }
386
262
 
387
- return bufferedExecTxs
388
- }
389
-
390
- function toVersionedTransaction(
391
- input: Transaction | TransactionInstruction[],
392
- payerKey: PublicKey,
393
- recentBlockhash: string,
394
- addressLookupTableAccounts?: AddressLookupTableAccount[],
395
- ): VersionedTransaction {
396
- const instructions: TransactionInstruction[] = Array.isArray(input) ? input : input.instructions
397
-
398
- const message = new TransactionMessage({ payerKey, recentBlockhash, instructions })
399
- return new VersionedTransaction(message.compileToV0Message(addressLookupTableAccounts))
263
+ return bufferedExecIxs
400
264
  }
401
265
 
402
266
  async function getManuallyExecuteInputs({
267
+ payer,
268
+ offramp,
403
269
  execReport,
404
- offrampProgram,
405
- transmitter,
406
270
  bufferId,
271
+ ...ctx
407
272
  }: {
273
+ payer: PublicKey
274
+ offramp: Program<typeof CCIP_OFFRAMP_IDL>
408
275
  execReport: ExecutionReport<CCIPMessage_V1_6_Solana>
409
- offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
410
- transmitter: string
411
276
  bufferId?: Buffer
412
- }) {
277
+ } & WithLogger) {
413
278
  const executionReport = prepareExecutionReport(execReport)
414
279
 
415
280
  const messageAccountMetas = execReport.message.accounts.map((acc, index) => {
@@ -430,8 +295,6 @@ async function getManuallyExecuteInputs({
430
295
  isWritable: false,
431
296
  }
432
297
 
433
- console.debug('Message receiver:', execReport.message.receiver)
434
-
435
298
  // Prepend receiver to messaging accounts
436
299
  const messagingAccounts: AccountMeta[] =
437
300
  execReport.message.receiver !== PublicKey.default.toBase58()
@@ -457,15 +320,16 @@ async function getManuallyExecuteInputs({
457
320
  addressLookupTableAccounts: addressLookupTables,
458
321
  tokenIndexes,
459
322
  } = await autoDeriveExecutionAccounts({
460
- offrampProgram,
323
+ offramp,
461
324
  originalSender: bytesToBuffer(execReport.message.sender),
462
- transmitter: new PublicKey(transmitter),
325
+ payer,
463
326
  messagingAccounts,
464
327
  sourceChainSelector: execReport.message.header.sourceChainSelector,
465
328
  tokenTransferAndOffchainData,
466
329
  merkleRoot: bytesToBuffer(execReport.merkleRoot),
467
330
  bufferId,
468
331
  tokenReceiver: new PublicKey(execReport.message.tokenReceiver),
332
+ ...ctx,
469
333
  })
470
334
 
471
335
  return {
@@ -518,19 +382,20 @@ function prepareExecutionReport({
518
382
  }
519
383
 
520
384
  async function autoDeriveExecutionAccounts({
521
- offrampProgram,
385
+ offramp,
522
386
  originalSender,
523
- transmitter,
387
+ payer,
524
388
  messagingAccounts,
525
389
  sourceChainSelector,
526
390
  tokenTransferAndOffchainData,
527
391
  merkleRoot,
528
392
  tokenReceiver,
529
393
  bufferId,
394
+ logger = console,
530
395
  }: {
531
- offrampProgram: Program<typeof CCIP_OFFRAMP_IDL>
396
+ offramp: Program<typeof CCIP_OFFRAMP_IDL>
532
397
  originalSender: Buffer
533
- transmitter: PublicKey
398
+ payer: PublicKey
534
399
  messagingAccounts: IdlTypes<typeof CCIP_OFFRAMP_IDL>['CcipAccountMeta'][]
535
400
  sourceChainSelector: bigint
536
401
  tokenTransferAndOffchainData: Array<
@@ -539,7 +404,7 @@ async function autoDeriveExecutionAccounts({
539
404
  merkleRoot: Buffer
540
405
  tokenReceiver: PublicKey
541
406
  bufferId?: Buffer
542
- }) {
407
+ } & WithLogger) {
543
408
  const derivedAccounts: AccountMeta[] = []
544
409
  const lookupTables: PublicKey[] = []
545
410
  const tokenIndices: number[] = []
@@ -547,14 +412,11 @@ async function autoDeriveExecutionAccounts({
547
412
  let stage = 'Start'
548
413
  let tokenIndex = 0
549
414
 
550
- const [configPDA] = PublicKey.findProgramAddressSync(
551
- [Buffer.from('config')],
552
- offrampProgram.programId,
553
- )
415
+ const [configPDA] = PublicKey.findProgramAddressSync([Buffer.from('config')], offramp.programId)
554
416
 
555
417
  while (true) {
556
418
  const params: IdlTypes<typeof CCIP_OFFRAMP_IDL>['DeriveAccountsExecuteParams'] = {
557
- executeCaller: transmitter,
419
+ executeCaller: payer,
558
420
  messageAccounts: messagingAccounts,
559
421
  sourceChainSelector: new BN(sourceChainSelector.toString()),
560
422
  originalSender: originalSender,
@@ -574,14 +436,8 @@ async function autoDeriveExecutionAccounts({
574
436
  }))
575
437
  }
576
438
 
577
- // copy of Program which avoids signing every simulation
578
- const readOnlyProgram = new Program(
579
- offrampProgram.idl,
580
- offrampProgram.programId,
581
- simulationProvider(offrampProgram.provider.connection, transmitter),
582
- )
583
439
  // Execute as a view call to get the response
584
- const response = (await readOnlyProgram.methods
440
+ const response = (await offramp.methods
585
441
  .deriveAccountsExecute(params, stage)
586
442
  .accounts({
587
443
  config: configPDA,
@@ -589,8 +445,8 @@ async function autoDeriveExecutionAccounts({
589
445
  .remainingAccounts(askWith)
590
446
  .view()
591
447
  .catch((error: unknown) => {
592
- console.error('Error deriving accounts:', error)
593
- console.error('Params:', params)
448
+ logger.error('Error deriving accounts:', error)
449
+ logger.error('Params:', params)
594
450
  throw error as Error
595
451
  })) as IdlTypes<typeof CCIP_OFFRAMP_IDL>['DeriveAccountsResponse']
596
452
 
@@ -604,7 +460,7 @@ async function autoDeriveExecutionAccounts({
604
460
  // Update token index
605
461
  tokenIndex += response.accountsToSave.length
606
462
 
607
- console.debug('After stage', stage, 'tokenIndices', tokenIndices, 'nextTokenIndex', tokenIndex)
463
+ logger.debug('After stage', stage, 'tokenIndices', tokenIndices, 'nextTokenIndex', tokenIndex)
608
464
 
609
465
  // Collect the derived accounts
610
466
  for (const meta of response.accountsToSave) {
@@ -633,9 +489,9 @@ async function autoDeriveExecutionAccounts({
633
489
  stage = response.nextStage
634
490
  }
635
491
 
636
- console.debug('Resulting derived accounts:', derivedAccounts)
637
- console.debug('Resulting derived address lookup tables:', lookupTables)
638
- console.debug('Resulting derived token indexes:', tokenIndices)
492
+ logger.debug('Resulting derived accounts:', derivedAccounts)
493
+ logger.debug('Resulting derived address lookup tables:', lookupTables)
494
+ logger.debug('Resulting derived token indexes:', tokenIndices)
639
495
 
640
496
  return {
641
497
  accounts: derivedAccounts,
@@ -10,10 +10,11 @@ import {
10
10
  toUtf8Bytes,
11
11
  zeroPadValue,
12
12
  } from 'ethers'
13
+ import type { ReadonlyDeep } from 'type-fest'
13
14
 
14
15
  import { decodeExtraArgs } from '../extra-args.ts'
15
16
  import type { LeafHasher } from '../hasher/index.ts'
16
- import { type CCIPMessage, type DeepReadonly, type Lane, CCIPVersion } from '../types.ts'
17
+ import { type CCIPMessage, type Lane, type WithLogger, CCIPVersion } from '../types.ts'
17
18
  import { getAddressBytes, getDataBytes, networkInfo, toLeArray } from '../utils.ts'
18
19
 
19
20
  const SvmExtraArgsSchema = {
@@ -37,11 +38,19 @@ const SvmTokenAmountsSchema = {
37
38
  },
38
39
  } as const
39
40
 
40
- export function getV16SolanaLeafHasher(lane: Lane): LeafHasher<typeof CCIPVersion.V1_6> {
41
+ /**
42
+ * Creates a leaf hasher for Solana v1.6 CCIP messages.
43
+ * @param lane - Lane configuration.
44
+ * @returns Leaf hasher function for Solana messages.
45
+ */
46
+ export function getV16SolanaLeafHasher(
47
+ lane: Lane,
48
+ { logger = console }: WithLogger = {},
49
+ ): LeafHasher<typeof CCIPVersion.V1_6> {
41
50
  if (lane.version !== CCIPVersion.V1_6)
42
51
  throw new Error(`Unsupported lane version: ${lane.version}`)
43
52
 
44
- return (message: DeepReadonly<CCIPMessage<typeof CCIPVersion.V1_6>>): string => {
53
+ return (message: ReadonlyDeep<CCIPMessage<typeof CCIPVersion.V1_6>>): string => {
45
54
  let parsedArgs
46
55
  if ('accountIsWritableBitmap' in message) {
47
56
  parsedArgs = {
@@ -95,7 +104,7 @@ export function getV16SolanaLeafHasher(lane: Lane): LeafHasher<typeof CCIPVersio
95
104
  ...[receiver].filter((a) => hexlify(a) !== ZeroHash),
96
105
  ...parsedArgs.accounts.map((a) => zeroPadValue(bs58.decode(a), 32)),
97
106
  ]
98
- console.debug(
107
+ logger.debug(
99
108
  'v1.6 solana leafHasher',
100
109
  packedValues.map((o) => (o instanceof Uint8Array ? `[${o.length}]:${hexlify(o)}` : o)),
101
110
  )