@boostxyz/sdk 7.1.0 → 7.3.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.
@@ -576,18 +576,25 @@ export class EventAction extends DeployableTarget<
576
576
  throw new ValidationAbiMissingError(signature);
577
577
  }
578
578
 
579
- let address: Address | undefined;
580
579
  if ('logs' in params) {
581
- for (let log of params.logs) {
580
+ const signatureMatchingLogs = params.logs
581
+ .filter((log) => log.topics[0] === signature)
582
+ .map((log) => decodeAndReorderLogArgs(event, log));
583
+
584
+ for (const log of signatureMatchingLogs) {
582
585
  if (!isAddressEqual(log.address, claimant.targetContract)) continue;
583
- let addressCandidate = this.validateClaimantAgainstArgs(
586
+ const addressCandidate = this.validateClaimantAgainstArgs(
584
587
  claimant,
585
588
  log,
586
589
  );
587
- if (addressCandidate) address = addressCandidate;
590
+ if (addressCandidate) return addressCandidate;
588
591
  }
589
- return address;
590
592
  }
593
+
594
+ if (!('hash' in params)) {
595
+ return undefined;
596
+ }
597
+
591
598
  const receipt = await getTransactionReceipt(this._config, {
592
599
  ...params,
593
600
  chainId: claimant.chainid,
@@ -611,9 +618,8 @@ export class EventAction extends DeployableTarget<
611
618
  for (let log of decodedLogs) {
612
619
  if (!isAddressEqual(log.address, claimant.targetContract)) continue;
613
620
  let addressCandidate = this.validateClaimantAgainstArgs(claimant, log);
614
- if (addressCandidate) address = addressCandidate;
621
+ if (addressCandidate) return addressCandidate;
615
622
  }
616
- return address;
617
623
  }
618
624
  if (claimant.signatureType === SignatureType.FUNC && 'hash' in params) {
619
625
  const transaction = await getTransaction(this._config, {
@@ -1252,6 +1258,139 @@ export class EventAction extends DeployableTarget<
1252
1258
  }
1253
1259
  return false;
1254
1260
  }
1261
+
1262
+ /**
1263
+ * Retrieves logs that match the criteria for event-based action steps.
1264
+ *
1265
+ * @public
1266
+ * @async
1267
+ * @param {ValidateActionStepParams} params - Parameters for fetching and filtering logs.
1268
+ * @returns {Promise<EventLog[]>} - A promise that resolves to an array of matching event logs.
1269
+ */
1270
+ public async getLogsForActionSteps(
1271
+ params: ValidateActionStepParams,
1272
+ ): Promise<EventLog[]> {
1273
+ const actionSteps = await this.getActionSteps();
1274
+ const actionStepLogs: EventLog[] = [];
1275
+
1276
+ for (const actionStep of actionSteps) {
1277
+ if (actionStep.signatureType === SignatureType.EVENT) {
1278
+ const logs = await this.getLogsForActionStep(actionStep, params);
1279
+ actionStepLogs.push(...logs);
1280
+ }
1281
+ }
1282
+ return actionStepLogs;
1283
+ }
1284
+
1285
+ /**
1286
+ * Finds logs that match the criteria for a specific action step.
1287
+ *
1288
+ * @public
1289
+ * @async
1290
+ * @param {ActionStep} actionStep - The action step to find logs for
1291
+ * @param {ValidateActionStepParams} params - Parameters for validation
1292
+ * @returns {Promise<EventLog[]>}
1293
+ */
1294
+ public async getLogsForActionStep(
1295
+ actionStep: ActionStep,
1296
+ params: ValidateActionStepParams,
1297
+ ): Promise<EventLog[]> {
1298
+ if (actionStep.signatureType !== SignatureType.EVENT) {
1299
+ return [];
1300
+ }
1301
+
1302
+ const signature = actionStep.signature;
1303
+ let event: AbiEvent;
1304
+ if (params.abiItem) event = params.abiItem as AbiEvent;
1305
+ else {
1306
+ const sigPool = params.knownSignatures as Record<Hex, AbiEvent>;
1307
+ event = sigPool[signature] as AbiEvent;
1308
+ }
1309
+
1310
+ if (!event) {
1311
+ throw new ValidationAbiMissingError(signature);
1312
+ }
1313
+
1314
+ if ('logs' in params) {
1315
+ return this.filterLogsByActionStepCriteria(
1316
+ actionStep,
1317
+ params.logs,
1318
+ event,
1319
+ );
1320
+ }
1321
+
1322
+ const receipt = await getTransactionReceipt(this._config, {
1323
+ ...params,
1324
+ chainId: actionStep.chainid,
1325
+ });
1326
+
1327
+ if (
1328
+ params.notBeforeBlockNumber &&
1329
+ receipt.blockNumber < params.notBeforeBlockNumber
1330
+ ) {
1331
+ return [];
1332
+ }
1333
+
1334
+ // Special handling for Transfer events
1335
+ if (actionStep.signature === TRANSFER_SIGNATURE) {
1336
+ const { decodedLogs, event } = await this.decodeTransferLogs(receipt);
1337
+ return this.filterLogsByActionStepCriteria(
1338
+ actionStep,
1339
+ decodedLogs,
1340
+ event,
1341
+ );
1342
+ }
1343
+
1344
+ const decodedLogs = receipt.logs
1345
+ .filter((log) => log.topics[0] === toEventSelector(event))
1346
+ .map((log) => decodeAndReorderLogArgs(event, log));
1347
+
1348
+ return this.filterLogsByActionStepCriteria(actionStep, decodedLogs, event);
1349
+ }
1350
+
1351
+ /**
1352
+ * Filters logs that meet the given action step criteria
1353
+ *
1354
+ * @private
1355
+ * @param {ActionStep} actionStep
1356
+ * @param {EventLogs} logs
1357
+ * @param {AbiEvent} eventAbi
1358
+ * @returns {EventLog[]}
1359
+ */
1360
+ private filterLogsByActionStepCriteria(
1361
+ actionStep: ActionStep,
1362
+ logs: EventLogs,
1363
+ eventAbi: AbiEvent,
1364
+ ): EventLog[] {
1365
+ const criteria = actionStep.actionParameter;
1366
+ const filteredLogs: EventLog[] = [];
1367
+
1368
+ if (!logs.length) return filteredLogs;
1369
+
1370
+ for (let log of logs) {
1371
+ if (!isAddressEqual(log.address, actionStep.targetContract)) continue;
1372
+
1373
+ try {
1374
+ if (!Array.isArray(log.args)) {
1375
+ continue;
1376
+ }
1377
+ const { value, type } = this.parseFieldFromAbi(
1378
+ log.args,
1379
+ criteria.fieldIndex,
1380
+ eventAbi.inputs || [],
1381
+ criteria.fieldType,
1382
+ );
1383
+ criteria.fieldType = type;
1384
+ if (this.validateFieldAgainstCriteria(criteria, value, { log })) {
1385
+ filteredLogs.push(log as EventLog);
1386
+ }
1387
+ } catch {
1388
+ // If there's an error on this log, keep trying with the next one
1389
+ }
1390
+ }
1391
+
1392
+ return filteredLogs;
1393
+ }
1255
1394
  }
1256
1395
 
1257
1396
  /**
@@ -1781,3 +1920,120 @@ export function decodeAndReorderLogArgs(event: AbiEvent, log: Log) {
1781
1920
  args: reorderedArgs,
1782
1921
  } as EventLog;
1783
1922
  }
1923
+
1924
+ /**
1925
+ * IMPORTANT: For variable incentive criteria use only.
1926
+ * Do NOT use for action steps - use {@link packFieldIndexes} instead.
1927
+ *
1928
+ * Packs two field indices into a single uint8 value for criteria tuple access.
1929
+ * Both indices must be between 0-13 to fit in the packed format.
1930
+ *
1931
+ * Uses an offset of 32 to avoid collision with normal field indices (which are 0-31),
1932
+ * allowing the system to distinguish between direct field access and tuple access.
1933
+ *
1934
+ * @export
1935
+ * @param {[number, number]} param0 - A tuple of [firstIndex, secondIndex]
1936
+ * @returns {number} - Packed uint8 value with base offset of 32
1937
+ * @throws {InvalidTupleEncodingError} - If either index is outside the valid range (0-13)
1938
+ */
1939
+ export function packCriteriaFieldIndexes([firstIndex, secondIndex]: [
1940
+ number,
1941
+ number,
1942
+ ]): number {
1943
+ if (
1944
+ firstIndex < 0 ||
1945
+ firstIndex > 13 ||
1946
+ secondIndex < 0 ||
1947
+ secondIndex > 13
1948
+ ) {
1949
+ throw new InvalidTupleEncodingError(
1950
+ `Tuple indices must be between 0-13, got: [${firstIndex}, ${secondIndex}]`,
1951
+ );
1952
+ }
1953
+ return 32 + (firstIndex << 4) + secondIndex;
1954
+ }
1955
+
1956
+ /**
1957
+ * Unpacks a uint8 packed index value into an array of indices.
1958
+ *
1959
+ * @export
1960
+ * @param {number} packed - Packed index value
1961
+ * @returns {[number, number]} - [firstIndex, secondIndex]
1962
+ */
1963
+ export function unpackCriteriaFieldIndexes(packed: number): [number, number] {
1964
+ if (packed < 32 || packed > 253) {
1965
+ throw new InvalidTupleEncodingError(
1966
+ `Field index must be between 32-253, got: ${packed}`,
1967
+ );
1968
+ }
1969
+
1970
+ const tupleValue = packed - 32;
1971
+ const firstIndex = (tupleValue >> 4) & 0xf;
1972
+ const secondIndex = tupleValue & 0xf;
1973
+ return [firstIndex, secondIndex];
1974
+ }
1975
+
1976
+ /**
1977
+ * Determines if a fieldIndex represents a tuple index (value >= 32) or a normal field index.
1978
+ *
1979
+ * @export
1980
+ * @param {number} fieldIndex - The field index to check
1981
+ * @returns {boolean} - True if it's a tuple index, false if it's a normal field index
1982
+ */
1983
+ export function isCriteriaFieldIndexTuple(fieldIndex: number): boolean {
1984
+ return fieldIndex >= 32;
1985
+ }
1986
+
1987
+ /**
1988
+ * Extracts a scalar value from a tuple within event or function arguments.
1989
+ * This is used for incentive criteria when determining reward amounts.
1990
+ *
1991
+ * @export
1992
+ * @param {unknown[]} args - The decoded arguments from an event or function call
1993
+ * @param {number} fieldIndex - The tuple-encoded index
1994
+ * @returns {bigint} The extracted scalar value as a bigint
1995
+ * @throws {DecodedArgsError} If arguments are missing or cannot be converted to bigint
1996
+ */
1997
+ export function getScalarValueFromTuple(
1998
+ args: unknown[],
1999
+ fieldIndex: number,
2000
+ ): bigint {
2001
+ if (!isCriteriaFieldIndexTuple(fieldIndex)) {
2002
+ throw new DecodedArgsError(
2003
+ `Field index ${fieldIndex} is invalid. Expected index >= 32`,
2004
+ );
2005
+ }
2006
+
2007
+ const [index0, index1] = unpackCriteriaFieldIndexes(fieldIndex);
2008
+
2009
+ if (index0 === undefined || index1 === undefined) {
2010
+ throw new DecodedArgsError(
2011
+ `Failed to unpack field indexes from ${fieldIndex}`,
2012
+ );
2013
+ }
2014
+
2015
+ if (!args || args.length <= index0) {
2016
+ throw new DecodedArgsError(`Decoded args missing item at index ${index0}`);
2017
+ }
2018
+
2019
+ const tuple = args[index0];
2020
+ if (!tuple || !Array.isArray(tuple)) {
2021
+ throw new DecodedArgsError(
2022
+ `Expected array at index ${index0}, but got ${typeof tuple}`,
2023
+ );
2024
+ }
2025
+ if (tuple.length <= index1) {
2026
+ throw new DecodedArgsError(
2027
+ `index ${index1} is out of bounds. tuple length is ${tuple.length}`,
2028
+ );
2029
+ }
2030
+
2031
+ const scalarValue = tuple[index1] as unknown;
2032
+ if (typeof scalarValue !== 'bigint') {
2033
+ throw new DecodedArgsError(
2034
+ `Expected bigint at tuple index ${index1}, but got ${typeof scalarValue}`,
2035
+ );
2036
+ }
2037
+
2038
+ return scalarValue;
2039
+ }
@@ -35,7 +35,12 @@ import {
35
35
  zeroHash,
36
36
  } from 'viem';
37
37
  import { ERC20PeggedVariableCriteriaIncentiveV2 as ERC20PeggedVariableCriteriaIncentiveV2Bases } from '../../dist/deployments.json';
38
- import { SignatureType } from '../Actions/EventAction';
38
+ import {
39
+ SignatureType,
40
+ decodeAndReorderLogArgs,
41
+ getScalarValueFromTuple,
42
+ isCriteriaFieldIndexTuple,
43
+ } from '../Actions/EventAction';
39
44
  import type {
40
45
  DeployableOptions,
41
46
  GenericDeployableParams,
@@ -231,25 +236,63 @@ export class ERC20PeggedVariableCriteriaIncentiveV2 extends DeployableTarget<
231
236
  * @throws {InvalidCriteriaTypeError | NoMatchingLogsError | DecodedArgsError}
232
237
  */
233
238
  public async getIncentiveScalar(
234
- { chainId, hash, knownSignatures }: GetIncentiveScalarV2Params,
239
+ { chainId, hash, knownSignatures, logs }: GetIncentiveScalarV2Params,
235
240
  params?: ReadParams,
236
241
  ): Promise<bigint> {
237
242
  const criteria = await this.getIncentiveCriteria(params);
238
243
  if (criteria.criteriaType === SignatureType.EVENT) {
239
- const transactionReceipt = await getTransactionReceipt(this._config, {
240
- chainId,
241
- hash,
242
- });
244
+ const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
245
+
243
246
  if (criteria.fieldIndex === CheatCodes.GAS_REBATE_INCENTIVE) {
247
+ const transactionReceipt = await getTransactionReceipt(this._config, {
248
+ chainId,
249
+ hash,
250
+ });
244
251
  const totalCost =
245
252
  transactionReceipt.gasUsed * transactionReceipt.effectiveGasPrice + // Normal gas cost
246
253
  (transactionReceipt.blobGasUsed ?? 0n) *
247
254
  (transactionReceipt.blobGasPrice ?? 0n); // Blob gas cost - account for potential undefined values
248
255
  return totalCost;
249
256
  }
250
- const logs = transactionReceipt.logs;
251
257
 
252
- if (logs.length === 0) {
258
+ // if logs are provided, use them to extract the scalar
259
+ if (logs && logs.length > 0) {
260
+ try {
261
+ // only check logs that match the criteria signature
262
+ const signatureMatchingLogs = logs
263
+ .filter((log) => log.topics && log.topics[0] === criteria.signature)
264
+ .map((log) => decodeAndReorderLogArgs(eventAbi, log));
265
+
266
+ if (signatureMatchingLogs.length > 0) {
267
+ for (const log of signatureMatchingLogs) {
268
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
269
+ return getScalarValueFromTuple(
270
+ log.args as unknown[],
271
+ criteria.fieldIndex,
272
+ );
273
+ }
274
+ const scalarValue = log.args
275
+ ? (log.args as string[])[criteria.fieldIndex]
276
+ : undefined;
277
+ if (scalarValue !== undefined) {
278
+ return BigInt(scalarValue);
279
+ }
280
+ }
281
+ }
282
+ } catch (e) {
283
+ throw new DecodedArgsError(
284
+ `An error occurred while extracting scalar from logs: ${(e as Error).message}`,
285
+ );
286
+ }
287
+ }
288
+
289
+ const transactionReceipt = await getTransactionReceipt(this._config, {
290
+ chainId,
291
+ hash,
292
+ });
293
+ const receiptLogs = transactionReceipt.logs;
294
+
295
+ if (receiptLogs.length === 0) {
253
296
  throw new NoMatchingLogsError(
254
297
  `No logs found for event signature ${criteria.signature}`,
255
298
  );
@@ -257,21 +300,28 @@ export class ERC20PeggedVariableCriteriaIncentiveV2 extends DeployableTarget<
257
300
 
258
301
  // Decode the event log
259
302
  try {
260
- // Decode function data
261
303
  const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
262
304
  const decodedEvents = parseEventLogs({
263
305
  abi: [eventAbi],
264
- logs,
306
+ logs: receiptLogs,
265
307
  });
266
308
  if (decodedEvents == undefined || decodedEvents.length === 0) {
267
309
  throw new NoMatchingLogsError(
268
310
  `No logs found for event signature ${criteria.signature}`,
269
311
  );
270
312
  }
271
- const scalarValue = (decodedEvents[0]?.args as string[])[
272
- criteria.fieldIndex
273
- ];
274
313
 
314
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
315
+ return getScalarValueFromTuple(
316
+ decodedEvents[0]?.args as unknown[],
317
+ criteria.fieldIndex,
318
+ );
319
+ }
320
+
321
+ const scalarValue =
322
+ decodedEvents[0] && decodedEvents[0].args
323
+ ? (decodedEvents[0].args as string[])[criteria.fieldIndex]
324
+ : undefined;
275
325
  if (scalarValue === undefined) {
276
326
  throw new DecodedArgsError(
277
327
  `Decoded argument at index ${criteria.fieldIndex} is undefined`,
@@ -296,6 +346,14 @@ export class ERC20PeggedVariableCriteriaIncentiveV2 extends DeployableTarget<
296
346
  abi: [func],
297
347
  data: transaction.input,
298
348
  });
349
+
350
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
351
+ return getScalarValueFromTuple(
352
+ decodedFunction.args as unknown[],
353
+ criteria.fieldIndex,
354
+ );
355
+ }
356
+
299
357
  const scalarValue = decodedFunction.args[criteria.fieldIndex] as string;
300
358
  if (scalarValue === undefined || scalarValue === null) {
301
359
  throw new DecodedArgsError(
@@ -9,6 +9,7 @@ import {
9
9
  type AbiEvent,
10
10
  type AbiFunction,
11
11
  type Address,
12
+ type GetLogsReturnType,
12
13
  type Hex,
13
14
  decodeAbiParameters,
14
15
  decodeFunctionData,
@@ -19,7 +20,13 @@ import {
19
20
  zeroHash,
20
21
  } from 'viem';
21
22
  import { ERC20VariableCriteriaIncentiveV2 as ERC20VariableCriteriaIncentiveV2Bases } from '../../dist/deployments.json';
22
- import { SignatureType, ValueType } from '../Actions/EventAction';
23
+ import {
24
+ SignatureType,
25
+ ValueType,
26
+ decodeAndReorderLogArgs,
27
+ getScalarValueFromTuple,
28
+ isCriteriaFieldIndexTuple,
29
+ } from '../Actions/EventAction';
23
30
  import type {
24
31
  DeployableOptions,
25
32
  GenericDeployableParams,
@@ -110,6 +117,7 @@ export interface GetIncentiveScalarV2Params {
110
117
  chainId: number;
111
118
  hash: Hex;
112
119
  knownSignatures: Record<Hex, AbiFunction | AbiEvent>;
120
+ logs?: GetLogsReturnType<AbiEvent, AbiEvent[], true>;
113
121
  }
114
122
 
115
123
  /**
@@ -242,25 +250,63 @@ export class ERC20VariableCriteriaIncentiveV2 extends ERC20VariableIncentive<
242
250
  * @throws {InvalidCriteriaTypeError | NoMatchingLogsError | DecodedArgsError}
243
251
  */
244
252
  public async getIncentiveScalar(
245
- { chainId, hash, knownSignatures }: GetIncentiveScalarV2Params,
253
+ { chainId, hash, knownSignatures, logs }: GetIncentiveScalarV2Params,
246
254
  params?: ReadParams,
247
255
  ): Promise<bigint> {
248
256
  const criteria = await this.getIncentiveCriteria(params);
249
257
  if (criteria.criteriaType === SignatureType.EVENT) {
250
- const transactionReceipt = await getTransactionReceipt(this._config, {
251
- chainId,
252
- hash,
253
- });
258
+ const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
259
+
254
260
  if (criteria.fieldIndex === CheatCodes.GAS_REBATE_INCENTIVE) {
261
+ const transactionReceipt = await getTransactionReceipt(this._config, {
262
+ chainId,
263
+ hash,
264
+ });
255
265
  const totalCost =
256
266
  transactionReceipt.gasUsed * transactionReceipt.effectiveGasPrice + // Normal gas cost
257
267
  (transactionReceipt.blobGasUsed ?? 0n) *
258
268
  (transactionReceipt.blobGasPrice ?? 0n); // Blob gas cost - account for potential undefined values
259
269
  return totalCost;
260
270
  }
261
- const logs = transactionReceipt.logs;
262
271
 
263
- if (logs.length === 0) {
272
+ // if logs are provided, use them to extract the scalar
273
+ if (logs && logs.length > 0) {
274
+ try {
275
+ // only check logs that match the criteria signature
276
+ const signatureMatchingLogs = logs
277
+ .filter((log) => log.topics && log.topics[0] === criteria.signature)
278
+ .map((log) => decodeAndReorderLogArgs(eventAbi, log));
279
+
280
+ if (signatureMatchingLogs.length > 0) {
281
+ for (const log of signatureMatchingLogs) {
282
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
283
+ return getScalarValueFromTuple(
284
+ log.args as unknown[],
285
+ criteria.fieldIndex,
286
+ );
287
+ }
288
+ const scalarValue = log.args
289
+ ? (log.args as string[])[criteria.fieldIndex]
290
+ : undefined;
291
+ if (scalarValue !== undefined) {
292
+ return BigInt(scalarValue);
293
+ }
294
+ }
295
+ }
296
+ } catch (e) {
297
+ throw new DecodedArgsError(
298
+ `An error occurred while extracting scalar from logs: ${(e as Error).message}`,
299
+ );
300
+ }
301
+ }
302
+
303
+ const transactionReceipt = await getTransactionReceipt(this._config, {
304
+ chainId,
305
+ hash,
306
+ });
307
+ const receiptLogs = transactionReceipt.logs;
308
+
309
+ if (receiptLogs.length === 0) {
264
310
  throw new NoMatchingLogsError(
265
311
  `No logs found for event signature ${criteria.signature}`,
266
312
  );
@@ -268,21 +314,28 @@ export class ERC20VariableCriteriaIncentiveV2 extends ERC20VariableIncentive<
268
314
 
269
315
  // Decode the event log
270
316
  try {
271
- // Decode function data
272
317
  const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
273
318
  const decodedEvents = parseEventLogs({
274
319
  abi: [eventAbi],
275
- logs,
320
+ logs: receiptLogs,
276
321
  });
277
322
  if (decodedEvents == undefined || decodedEvents.length === 0) {
278
323
  throw new NoMatchingLogsError(
279
324
  `No logs found for event signature ${criteria.signature}`,
280
325
  );
281
326
  }
282
- const scalarValue = (decodedEvents[0]?.args as string[])[
283
- criteria.fieldIndex
284
- ];
285
327
 
328
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
329
+ return getScalarValueFromTuple(
330
+ decodedEvents[0]?.args as unknown[],
331
+ criteria.fieldIndex,
332
+ );
333
+ }
334
+
335
+ const scalarValue =
336
+ decodedEvents[0] && decodedEvents[0].args
337
+ ? (decodedEvents[0].args as string[])[criteria.fieldIndex]
338
+ : undefined;
286
339
  if (scalarValue === undefined) {
287
340
  throw new DecodedArgsError(
288
341
  `Decoded argument at index ${criteria.fieldIndex} is undefined`,
@@ -307,6 +360,14 @@ export class ERC20VariableCriteriaIncentiveV2 extends ERC20VariableIncentive<
307
360
  abi: [func],
308
361
  data: transaction.input,
309
362
  });
363
+
364
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
365
+ return getScalarValueFromTuple(
366
+ decodedFunction.args as unknown[],
367
+ criteria.fieldIndex,
368
+ );
369
+ }
370
+
310
371
  const scalarValue = decodedFunction.args[criteria.fieldIndex] as string;
311
372
  if (scalarValue === undefined || scalarValue === null) {
312
373
  throw new DecodedArgsError(