@chainlink/ccip-sdk 1.1.0 → 1.2.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 (115) hide show
  1. package/dist/api/index.d.ts +165 -15
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +236 -61
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/types.d.ts +119 -1
  6. package/dist/api/types.d.ts.map +1 -1
  7. package/dist/aptos/index.d.ts.map +1 -1
  8. package/dist/aptos/index.js +5 -5
  9. package/dist/aptos/index.js.map +1 -1
  10. package/dist/chain.d.ts +65 -24
  11. package/dist/chain.d.ts.map +1 -1
  12. package/dist/chain.js +84 -11
  13. package/dist/chain.js.map +1 -1
  14. package/dist/errors/codes.d.ts +1 -0
  15. package/dist/errors/codes.d.ts.map +1 -1
  16. package/dist/errors/codes.js +1 -0
  17. package/dist/errors/codes.js.map +1 -1
  18. package/dist/errors/index.d.ts +1 -1
  19. package/dist/errors/index.d.ts.map +1 -1
  20. package/dist/errors/index.js +1 -1
  21. package/dist/errors/index.js.map +1 -1
  22. package/dist/errors/recovery.d.ts.map +1 -1
  23. package/dist/errors/recovery.js +1 -0
  24. package/dist/errors/recovery.js.map +1 -1
  25. package/dist/errors/specialized.d.ts +21 -0
  26. package/dist/errors/specialized.d.ts.map +1 -1
  27. package/dist/errors/specialized.js +31 -1
  28. package/dist/errors/specialized.js.map +1 -1
  29. package/dist/evm/abi/OffRamp_2_0.d.ts +18 -17
  30. package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -1
  31. package/dist/evm/abi/OffRamp_2_0.js +19 -21
  32. package/dist/evm/abi/OffRamp_2_0.js.map +1 -1
  33. package/dist/evm/abi/TokenPool_2_0.d.ts +0 -4
  34. package/dist/evm/abi/TokenPool_2_0.d.ts.map +1 -1
  35. package/dist/evm/abi/TokenPool_2_0.js +0 -1
  36. package/dist/evm/abi/TokenPool_2_0.js.map +1 -1
  37. package/dist/evm/gas.d.ts +14 -4
  38. package/dist/evm/gas.d.ts.map +1 -1
  39. package/dist/evm/gas.js +7 -6
  40. package/dist/evm/gas.js.map +1 -1
  41. package/dist/evm/index.d.ts +39 -8
  42. package/dist/evm/index.d.ts.map +1 -1
  43. package/dist/evm/index.js +106 -36
  44. package/dist/evm/index.js.map +1 -1
  45. package/dist/extra-args.d.ts +18 -8
  46. package/dist/extra-args.d.ts.map +1 -1
  47. package/dist/extra-args.js +6 -6
  48. package/dist/extra-args.js.map +1 -1
  49. package/dist/gas.d.ts +1 -1
  50. package/dist/gas.d.ts.map +1 -1
  51. package/dist/gas.js +7 -2
  52. package/dist/gas.js.map +1 -1
  53. package/dist/index.d.ts +3 -2
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/requests.d.ts +11 -5
  57. package/dist/requests.d.ts.map +1 -1
  58. package/dist/requests.js +4 -7
  59. package/dist/requests.js.map +1 -1
  60. package/dist/solana/index.d.ts +2 -2
  61. package/dist/solana/index.d.ts.map +1 -1
  62. package/dist/solana/index.js +3 -2
  63. package/dist/solana/index.js.map +1 -1
  64. package/dist/solana/utils.js +2 -2
  65. package/dist/solana/utils.js.map +1 -1
  66. package/dist/sui/exec.d.ts +30 -0
  67. package/dist/sui/exec.d.ts.map +1 -0
  68. package/dist/sui/exec.js +92 -0
  69. package/dist/sui/exec.js.map +1 -0
  70. package/dist/sui/index.d.ts +7 -2
  71. package/dist/sui/index.d.ts.map +1 -1
  72. package/dist/sui/index.js +23 -65
  73. package/dist/sui/index.js.map +1 -1
  74. package/dist/sui/manuallyExec/index.d.ts.map +1 -1
  75. package/dist/sui/manuallyExec/index.js +10 -13
  76. package/dist/sui/manuallyExec/index.js.map +1 -1
  77. package/dist/sui/objects.d.ts.map +1 -1
  78. package/dist/sui/objects.js +4 -2
  79. package/dist/sui/objects.js.map +1 -1
  80. package/dist/sui/types.d.ts +9 -1
  81. package/dist/sui/types.d.ts.map +1 -1
  82. package/dist/sui/types.js.map +1 -1
  83. package/dist/ton/index.d.ts.map +1 -1
  84. package/dist/ton/index.js +34 -26
  85. package/dist/ton/index.js.map +1 -1
  86. package/dist/utils.d.ts +10 -4
  87. package/dist/utils.d.ts.map +1 -1
  88. package/dist/utils.js +10 -4
  89. package/dist/utils.js.map +1 -1
  90. package/package.json +7 -7
  91. package/src/api/index.ts +271 -59
  92. package/src/api/types.ts +126 -1
  93. package/src/aptos/index.ts +7 -9
  94. package/src/chain.ts +136 -38
  95. package/src/errors/codes.ts +1 -0
  96. package/src/errors/index.ts +1 -0
  97. package/src/errors/recovery.ts +2 -0
  98. package/src/errors/specialized.ts +33 -1
  99. package/src/evm/abi/OffRamp_2_0.ts +19 -21
  100. package/src/evm/abi/TokenPool_2_0.ts +0 -1
  101. package/src/evm/gas.ts +18 -20
  102. package/src/evm/index.ts +126 -34
  103. package/src/extra-args.ts +18 -8
  104. package/src/gas.ts +8 -3
  105. package/src/index.ts +5 -0
  106. package/src/requests.ts +18 -12
  107. package/src/solana/index.ts +3 -2
  108. package/src/solana/utils.ts +2 -2
  109. package/src/sui/exec.ts +131 -0
  110. package/src/sui/index.ts +33 -98
  111. package/src/sui/manuallyExec/index.ts +11 -17
  112. package/src/sui/objects.ts +4 -2
  113. package/src/sui/types.ts +10 -1
  114. package/src/ton/index.ts +47 -26
  115. package/src/utils.ts +10 -4
package/src/sui/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { bcs } from '@mysten/sui/bcs'
2
- import { type SuiTransactionBlockResponse, SuiClient } from '@mysten/sui/client'
2
+ import { SuiClient } from '@mysten/sui/client'
3
3
  import type { Keypair } from '@mysten/sui/cryptography'
4
4
  import { SuiGraphQLClient } from '@mysten/sui/graphql'
5
5
  import { Transaction } from '@mysten/sui/transactions'
@@ -17,20 +17,13 @@ import {
17
17
  import { getCcipStateAddress, getOffRampForCcip } from './discovery.ts'
18
18
  import { type CommitEvent, streamSuiLogs } from './events.ts'
19
19
  import { getSuiLeafHasher } from './hasher.ts'
20
- import {
21
- deriveObjectID,
22
- fetchTokenConfigs,
23
- getLatestPackageId,
24
- getObjectRef,
25
- getReceiverModule,
26
- } from './objects.ts'
20
+ import { deriveObjectID, getLatestPackageId, getObjectRef } from './objects.ts'
27
21
  import {
28
22
  CCIPArgumentInvalidError,
29
23
  CCIPContractNotRouterError,
30
24
  CCIPDataFormatUnsupportedError,
31
25
  CCIPError,
32
26
  CCIPErrorCode,
33
- CCIPExecTxRevertedError,
34
27
  CCIPExecutionReportChainMismatchError,
35
28
  CCIPLogsAddressRequiredError,
36
29
  CCIPNotImplementedError,
@@ -47,7 +40,6 @@ import {
47
40
  type CCIPExecution,
48
41
  type CCIPMessage,
49
42
  type CCIPRequest,
50
- type CCIPVersion,
51
43
  type ChainLog,
52
44
  type ChainTransaction,
53
45
  type CommitReport,
@@ -67,12 +59,9 @@ import {
67
59
  parseTypeAndVersion,
68
60
  util,
69
61
  } from '../utils.ts'
70
- import {
71
- type SuiManuallyExecuteInput,
72
- type TokenConfig,
73
- buildManualExecutionPTB,
74
- } from './manuallyExec/index.ts'
75
- import type { CCIPMessage_V1_6_Sui } from './types.ts'
62
+ import { generateUnsignedExecutePTB, signAndExecuteSuiTx } from './exec.ts'
63
+ import type { CCIPMessage_V1_6_Sui, UnsignedSuiTx } from './types.ts'
64
+ export type { UnsignedSuiTx }
76
65
 
77
66
  const DEFAULT_GAS_LIMIT = 1000000n
78
67
 
@@ -728,11 +717,28 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
728
717
  return Promise.reject(new CCIPNotImplementedError('SuiChain.sendMessage'))
729
718
  }
730
719
 
731
- /** {@inheritDoc Chain.generateUnsignedExecute} */
732
- override generateUnsignedExecute(
733
- _opts: Parameters<Chain['generateUnsignedExecute']>[0],
734
- ): Promise<never> {
735
- return Promise.reject(new CCIPNotImplementedError('SuiChain.generateUnsignedExecute'))
720
+ /**
721
+ * {@inheritDoc Chain.generateUnsignedExecute}
722
+ * @throws {@link CCIPExecutionReportChainMismatchError} if input is not a Sui v1.6 execution report
723
+ */
724
+ override async generateUnsignedExecute(
725
+ opts: Parameters<Chain['generateUnsignedExecute']>[0],
726
+ ): Promise<UnsignedSuiTx> {
727
+ const resolved = await this.resolveExecuteOpts(opts)
728
+ if (!resolved.offRamp.includes('::')) resolved.offRamp += '::offramp'
729
+ if (!('message' in resolved.input)) {
730
+ throw new CCIPExecutionReportChainMismatchError('Sui')
731
+ }
732
+
733
+ return generateUnsignedExecutePTB(
734
+ this.client,
735
+ resolved.offRamp,
736
+ resolved.input as ExecutionInput<CCIPMessage_V1_6_Sui>,
737
+ {
738
+ gasLimit: resolved.gasLimit,
739
+ receiverObjectIds: (resolved as { receiverObjectIds?: string[] }).receiverObjectIds,
740
+ },
741
+ )
736
742
  }
737
743
 
738
744
  /**
@@ -745,94 +751,23 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
745
751
  receiverObjectIds?: string[]
746
752
  },
747
753
  ): Promise<CCIPExecution> {
748
- if (!('input' in opts && 'message' in opts.input)) {
749
- throw new CCIPExecutionReportChainMismatchError('Sui')
750
- }
751
- const { input, offRamp } = opts
752
754
  const wallet = opts.wallet as Keypair
753
755
 
754
- // Discover the CCIP package from the offramp
755
- const ccip = await getCcipStateAddress(offRamp, this.client)
756
-
757
- const ccipObjectRef = await getObjectRef(ccip, this.client)
758
- const offrampStateObject = await getObjectRef(offRamp, this.client)
759
- const receiverConfig = await getReceiverModule(
760
- this.client,
761
- ccip,
762
- ccipObjectRef,
763
- input.message.receiver,
764
- )
765
- let tokenConfigs: TokenConfig[] = []
766
- if (input.message.tokenAmounts.length !== 0) {
767
- tokenConfigs = await fetchTokenConfigs(
768
- this.client,
769
- ccip,
770
- ccipObjectRef,
771
- input.message.tokenAmounts as CCIPMessage<typeof CCIPVersion.V1_6>['tokenAmounts'],
772
- )
773
- }
774
-
775
- const suiInput: SuiManuallyExecuteInput = {
776
- executionReport: input as ExecutionInput<CCIPMessage_V1_6_Sui>,
777
- offrampAddress: offRamp,
778
- ccipAddress: ccip,
779
- ccipObjectRef,
780
- offrampStateObject,
781
- receiverConfig,
782
- tokenConfigs,
783
- }
784
756
  if (opts.receiverObjectIds) {
785
757
  this.logger.info(
786
758
  `Overriding Sui Manual Execution receiverObjectIds with: ${opts.receiverObjectIds.join(', ')}`,
787
759
  )
788
- suiInput.overrideReceiverObjectIds = opts.receiverObjectIds
789
760
  }
790
- const tx = buildManualExecutionPTB(suiInput)
791
761
 
792
- // Set gas budget if provided
793
- if (opts.gasLimit) {
794
- tx.setGasBudget(opts.gasLimit)
795
- }
796
-
797
- this.logger.info(`Executing Sui CCIP execute transaction...`)
798
- // Sign and execute the transaction
799
- let result: SuiTransactionBlockResponse
800
- try {
801
- result = await this.client.signAndExecuteTransaction({
802
- signer: wallet,
803
- transaction: tx,
804
- options: {
805
- showEffects: true,
806
- showEvents: true,
807
- },
808
- })
809
- } catch (e) {
810
- throw new CCIPError(
811
- CCIPErrorCode.TRANSACTION_NOT_FINALIZED,
812
- `Failed to send Sui execute transaction: ${(e as Error).message}`,
813
- )
814
- }
815
-
816
- // Check if transaction inmediately reverted
817
- if (result.effects?.status.status !== 'success') {
818
- const errorMsg = result.effects?.status.error || 'Unknown error'
819
- throw new CCIPExecTxRevertedError(result.digest, {
820
- context: { error: errorMsg },
821
- })
822
- }
823
-
824
- this.logger.info(`Waiting for Sui transaction ${result.digest} to be finalized...`)
825
-
826
- await this.client.waitForTransaction({
827
- digest: result.digest,
828
- options: {
829
- showEffects: true,
830
- showEvents: true,
831
- },
762
+ const unsignedTx = await this.generateUnsignedExecute({
763
+ ...opts,
764
+ payer: '',
832
765
  })
833
766
 
767
+ const digest = await signAndExecuteSuiTx(this.client, wallet, unsignedTx, this.logger)
768
+
834
769
  // Return the transaction as a ChainTransaction
835
- return this.getExecutionReceiptInTx(await this.getTransaction(result.digest))
770
+ return this.getExecutionReceiptInTx(await this.getTransaction(digest))
836
771
  }
837
772
 
838
773
  /**
@@ -4,9 +4,7 @@ import { Transaction } from '@mysten/sui/transactions'
4
4
 
5
5
  import { serializeExecutionReport } from './encoder.ts'
6
6
  import { CCIPMessageInvalidError } from '../../errors/specialized.ts'
7
- import { decodeExtraArgs } from '../../extra-args.ts'
8
7
  import type { ExecutionInput } from '../../types.ts'
9
- import { networkInfo } from '../../utils.ts'
10
8
  import type { CCIPMessage_V1_6_Sui } from '../types.ts'
11
9
 
12
10
  /** Configuration for manually executing a Sui receiver module. */
@@ -56,12 +54,16 @@ export function buildManualExecutionPTB({
56
54
  }: SuiManuallyExecuteInput): Transaction {
57
55
  const reportBytes = serializeExecutionReport(executionReport)
58
56
 
57
+ // Strip any ::module suffixes to get bare package IDs for move call targets
58
+ const offrampPackageId = offrampAddress.split('::')[0]!
59
+ const ccipPackageId = ccipAddress.split('::')[0]!
60
+
59
61
  // Create transaction
60
62
  const tx = new Transaction()
61
63
 
62
64
  // Step 1: Call manually_init_execute to prepare the execution
63
65
  const receiverParamsArg = tx.moveCall({
64
- target: `${offrampAddress}::offramp::manually_init_execute`,
66
+ target: `${offrampPackageId}::offramp::manually_init_execute`,
65
67
  arguments: [
66
68
  tx.object(ccipObjectRef),
67
69
  tx.object(offrampStateObject),
@@ -72,7 +74,7 @@ export function buildManualExecutionPTB({
72
74
 
73
75
  // Get the message from the from the report using the offramp helper
74
76
  const messageArg = tx.moveCall({
75
- target: `${ccipAddress}::offramp_state_helper::extract_any2sui_message`,
77
+ target: `${ccipPackageId}::offramp_state_helper::extract_any2sui_message`,
76
78
  arguments: [receiverParamsArg],
77
79
  })
78
80
 
@@ -96,17 +98,9 @@ export function buildManualExecutionPTB({
96
98
  }
97
99
  }
98
100
 
99
- // Decode extraArgs to get receiverObjectIds
100
- const decodedExtraArgs = decodeExtraArgs(
101
- executionReport.message.extraArgs,
102
- networkInfo(executionReport.message.destChainSelector).family,
103
- )
104
-
105
- if (!decodedExtraArgs || decodedExtraArgs._tag !== 'SuiExtraArgsV1') {
106
- throw new CCIPMessageInvalidError('Expected Sui extra args')
107
- }
101
+ const { receiverObjectIds } = executionReport.message
108
102
 
109
- if (decodedExtraArgs.receiverObjectIds.length === 0) {
103
+ if (receiverObjectIds.length === 0) {
110
104
  throw new CCIPMessageInvalidError('No receiverObjectIds provided in SUIExtraArgsV1')
111
105
  }
112
106
  // Call the receiver contract
@@ -116,16 +110,16 @@ export function buildManualExecutionPTB({
116
110
  tx.pure.vector('u8', Buffer.from(executionReport.message.messageId.slice(2), 'hex')),
117
111
  tx.object(ccipObjectRef),
118
112
  messageArg,
119
- // if overrideReceiverObjectIds is provided, use them; otherwise, use the ones from decodedExtraArgs (original message)
113
+ // if overrideReceiverObjectIds is provided, use them; otherwise, use the ones from the message
120
114
  ...(overrideReceiverObjectIds && overrideReceiverObjectIds.length > 0
121
115
  ? overrideReceiverObjectIds.map(tx.object)
122
- : decodedExtraArgs.receiverObjectIds.map(tx.object)),
116
+ : receiverObjectIds.map(tx.object)),
123
117
  ],
124
118
  })
125
119
 
126
120
  // Step 2: Call finish_execute to complete the execution
127
121
  tx.moveCall({
128
- target: `${offrampAddress}::offramp::finish_execute`,
122
+ target: `${offrampPackageId}::offramp::finish_execute`,
129
123
  arguments: [
130
124
  tx.object(ccipObjectRef),
131
125
  tx.object(offrampStateObject),
@@ -135,11 +135,12 @@ export async function getReceiverModule(
135
135
  ccipObjectRef: string,
136
136
  receiverPackageId: string,
137
137
  ) {
138
+ const ccipBarePackageId = ccipPackageId.split('::')[0]!
138
139
  // Call get_receiver_config from receiver_registry contract
139
140
  const tx = new Transaction()
140
141
 
141
142
  tx.moveCall({
142
- target: `${ccipPackageId}::receiver_registry::get_receiver_config`,
143
+ target: `${ccipBarePackageId}::receiver_registry::get_receiver_config`,
143
144
  arguments: [tx.object(ccipObjectRef), tx.pure.address(receiverPackageId)],
144
145
  })
145
146
 
@@ -207,12 +208,13 @@ export async function fetchTokenConfigs(
207
208
  ]
208
209
 
209
210
  // Fetch token config for each unique token address
211
+ const ccipBarePackageId = ccipPackageId.split('::')[0]!
210
212
  for (const tokenAddress of tokenAddresses) {
211
213
  const tx = new Transaction()
212
214
 
213
215
  // Call get_token_config_struct from token_admin_registry
214
216
  tx.moveCall({
215
- target: `${ccipPackageId}::token_admin_registry::get_token_config_struct`,
217
+ target: `${ccipBarePackageId}::token_admin_registry::get_token_config_struct`,
216
218
  arguments: [tx.object(ccipObjectRef), tx.pure.address(tokenAddress)],
217
219
  })
218
220
 
package/src/sui/types.ts CHANGED
@@ -2,12 +2,21 @@ import { bcs } from '@mysten/sui/bcs'
2
2
  import { concat } from 'ethers'
3
3
 
4
4
  import { type SuiExtraArgsV1, SuiExtraArgsV1Tag } from '../extra-args.ts'
5
- import type { CCIPMessage_V1_6 } from '../types.ts'
5
+ import type { CCIPMessage_V1_6, ChainFamily } from '../types.ts'
6
6
  import { getAddressBytes, getDataBytes } from '../utils.ts'
7
7
 
8
8
  /** Sui-specific CCIP v1.6 message type with Sui extra args. */
9
9
  export type CCIPMessage_V1_6_Sui = CCIPMessage_V1_6 & SuiExtraArgsV1
10
10
 
11
+ /**
12
+ * Unsigned Sui transaction, serialized via Transaction#serialize().
13
+ * Reconstruct with Transaction.from(transactions[0]).
14
+ */
15
+ export type UnsignedSuiTx = {
16
+ family: typeof ChainFamily.Sui
17
+ transactions: [string]
18
+ }
19
+
11
20
  export const SuiExtraArgsV1Codec = bcs.struct('SuiExtraArgsV1', {
12
21
  gasLimit: bcs.u64(),
13
22
  allowOutOfOrderExecution: bcs.bool(),
package/src/ton/index.ts CHANGED
@@ -3,7 +3,18 @@ import { Buffer } from 'buffer'
3
3
  import { type Transaction, Address, Cell, beginCell, toNano } from '@ton/core'
4
4
  import { TonClient } from '@ton/ton'
5
5
  import { type AxiosAdapter, getAdapter } from 'axios'
6
- import { type BytesLike, hexlify, isBytesLike, isHexString, toBeArray, toBeHex } from 'ethers'
6
+ import {
7
+ type BytesLike,
8
+ concat,
9
+ dataLength,
10
+ dataSlice,
11
+ hexlify,
12
+ isBytesLike,
13
+ isHexString,
14
+ toBeArray,
15
+ toBeHex,
16
+ toBigInt,
17
+ } from 'ethers'
7
18
  import { type Memoized, memoize } from 'micro-memoize'
8
19
  import type { PickDeep } from 'type-fest'
9
20
 
@@ -45,6 +56,7 @@ import {
45
56
  bytesToBuffer,
46
57
  createRateLimitedFetch,
47
58
  decodeAddress,
59
+ getDataBytes,
48
60
  networkInfo,
49
61
  parseTypeAndVersion,
50
62
  sleep,
@@ -64,6 +76,16 @@ function isTvmError(error: unknown): error is Error & { exitCode: number } {
64
76
  return error instanceof Error && 'exitCode' in error && typeof error.exitCode === 'number'
65
77
  }
66
78
 
79
+ function bitsToBytes(bits: string): Uint8Array {
80
+ return Uint8Array.from(bits.match(/.{1,8}/g)!.map((byte) => parseInt(byte.padEnd(8, '0'), 2)))
81
+ }
82
+
83
+ function bytesToBits(bytes: Uint8Array): string {
84
+ return Array.from(bytes)
85
+ .map((B) => B.toString(2).padStart(8, '0'))
86
+ .join('')
87
+ }
88
+
67
89
  /**
68
90
  * TON chain implementation supporting TON networks.
69
91
  *
@@ -702,14 +724,14 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
702
724
  */
703
725
  static encodeExtraArgs(args: ExtraArgs): string {
704
726
  if ('gasLimit' in args && 'allowOutOfOrderExecution' in args) {
705
- const cell = beginCell()
706
- .storeUint(Number(EVMExtraArgsV2Tag), 32) // magic tag
707
- .storeUint(args.gasLimit, 256) // gasLimit
708
- .storeBit(args.allowOutOfOrderExecution) // bool
709
- .endCell()
710
-
711
- // Return full BOC including headers
712
- return '0x' + cell.toBoc().toString('hex')
727
+ return concat([
728
+ EVMExtraArgsV2Tag,
729
+ bitsToBytes(
730
+ '1' +
731
+ bytesToBits(toBeArray(args.gasLimit, 32)) +
732
+ (args.allowOutOfOrderExecution ? '1' : '0'),
733
+ ),
734
+ ])
713
735
  }
714
736
  return '0x'
715
737
  }
@@ -729,25 +751,24 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
729
751
  static decodeExtraArgs(
730
752
  extraArgs: BytesLike,
731
753
  ): (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' }) | undefined {
732
- const data = bytesToBuffer(extraArgs)
733
-
734
- try {
735
- // Parse BOC format to extract cell data
736
- const cell = Cell.fromBoc(data)[0]!
737
- const slice = cell.beginParse()
754
+ if (dataSlice(extraArgs, 0, 4) !== EVMExtraArgsV2Tag || dataLength(extraArgs) < 5) return
755
+ const data = getDataBytes(extraArgs).subarray(4)
756
+ let bits = bytesToBits(data)
757
+ let gasLimit = 0n
758
+ if (bits[0] === '1') {
759
+ if (bits.length < 1 + 32 * 8) return
760
+ gasLimit = toBigInt(bitsToBytes(bits.substring(1, 1 + 32 * 8)))
761
+ bits = bits.substring(1 + 32 * 8)
762
+ } else {
763
+ bits = bits.substring(1)
764
+ }
738
765
 
739
- // Load and verify magic tag to ensure correct extra args type
740
- const magicTag = slice.loadUint(32)
741
- if (magicTag !== Number(EVMExtraArgsV2Tag)) return undefined
766
+ const allowOutOfOrderExecution = bits[0] === '1'
742
767
 
743
- return {
744
- _tag: 'EVMExtraArgsV2',
745
- gasLimit: slice.loadUintBig(256),
746
- allowOutOfOrderExecution: slice.loadBit(),
747
- }
748
- } catch {
749
- // Return undefined for any parsing errors (invalid BOC, malformed data, etc.)
750
- return undefined
768
+ return {
769
+ _tag: 'EVMExtraArgsV2',
770
+ gasLimit,
771
+ allowOutOfOrderExecution,
751
772
  }
752
773
  }
753
774
 
package/src/utils.ts CHANGED
@@ -190,10 +190,16 @@ export const networkInfo = memoize(function networkInfo_(
190
190
 
191
191
  const BLOCK_RANGE = 10_000
192
192
  /**
193
- * Generates exclusive block ranges [fromBlock, toBlock]
194
- * If startBlock is given, moves forward from there (up to latestBlock),
195
- * Otherwise, moves backwards down to genesis (you probably want to break/return before that)
196
- **/
193
+ * Generates block ranges for paginated log queries.
194
+ *
195
+ * @param params - Range parameters:
196
+ * - `singleBlock` - yields a single `{ fromBlock, toBlock }` for that block.
197
+ * - `endBlock` + optional `startBlock` - if `startBlock` is given, moves forward
198
+ * from there up to `endBlock`; otherwise moves backward from `endBlock` to genesis.
199
+ * - `page` - step size per range (default 10 000).
200
+ * @returns Generator of `{ fromBlock, toBlock }` pairs, optionally with a `progress` percentage
201
+ * string when iterating forward.
202
+ */
197
203
  export function* blockRangeGenerator(
198
204
  params: { page?: number } & ({ endBlock: number; startBlock?: number } | { singleBlock: number }),
199
205
  ) {