@boostxyz/sdk 0.0.0-alpha.11 → 0.0.0-alpha.13

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 (154) hide show
  1. package/dist/Actions/Action.cjs +1 -1
  2. package/dist/Actions/Action.js +1 -1
  3. package/dist/Actions/ContractAction.d.ts +2 -2
  4. package/dist/Actions/ContractAction.d.ts.map +1 -1
  5. package/dist/Actions/ERC721MintAction.d.ts +2 -2
  6. package/dist/Actions/ERC721MintAction.d.ts.map +1 -1
  7. package/dist/Actions/EventAction.cjs +1 -1
  8. package/dist/Actions/EventAction.cjs.map +1 -1
  9. package/dist/Actions/EventAction.d.ts +117 -33
  10. package/dist/Actions/EventAction.d.ts.map +1 -1
  11. package/dist/Actions/EventAction.js +309 -121
  12. package/dist/Actions/EventAction.js.map +1 -1
  13. package/dist/AllowLists/AllowList.cjs +1 -1
  14. package/dist/AllowLists/AllowList.js +2 -2
  15. package/dist/AllowLists/SimpleAllowList.cjs +1 -1
  16. package/dist/AllowLists/SimpleAllowList.cjs.map +1 -1
  17. package/dist/AllowLists/SimpleAllowList.d.ts +2 -2
  18. package/dist/AllowLists/SimpleAllowList.d.ts.map +1 -1
  19. package/dist/AllowLists/SimpleAllowList.js +23 -19
  20. package/dist/AllowLists/SimpleAllowList.js.map +1 -1
  21. package/dist/AllowLists/SimpleDenyList.cjs +1 -1
  22. package/dist/AllowLists/SimpleDenyList.d.ts +2 -2
  23. package/dist/AllowLists/SimpleDenyList.d.ts.map +1 -1
  24. package/dist/AllowLists/SimpleDenyList.js +6 -5
  25. package/dist/AllowLists/SimpleDenyList.js.map +1 -1
  26. package/dist/Auth/PassthroughAuth.cjs +1 -1
  27. package/dist/Auth/PassthroughAuth.js +1 -1
  28. package/dist/BoostCore.cjs +2 -2
  29. package/dist/BoostCore.cjs.map +1 -1
  30. package/dist/BoostCore.d.ts +27 -5
  31. package/dist/BoostCore.d.ts.map +1 -1
  32. package/dist/BoostCore.js +438 -347
  33. package/dist/BoostCore.js.map +1 -1
  34. package/dist/BoostRegistry.cjs +1 -1
  35. package/dist/BoostRegistry.cjs.map +1 -1
  36. package/dist/BoostRegistry.d.ts +26 -5
  37. package/dist/BoostRegistry.d.ts.map +1 -1
  38. package/dist/BoostRegistry.js +125 -64
  39. package/dist/BoostRegistry.js.map +1 -1
  40. package/dist/Budgets/Budget.cjs +1 -1
  41. package/dist/Budgets/Budget.js +1 -1
  42. package/dist/Budgets/ManagedBudget.cjs +1 -1
  43. package/dist/Budgets/ManagedBudget.cjs.map +1 -1
  44. package/dist/Budgets/ManagedBudget.d.ts +2 -2
  45. package/dist/Budgets/ManagedBudget.d.ts.map +1 -1
  46. package/dist/Budgets/ManagedBudget.js +41 -37
  47. package/dist/Budgets/ManagedBudget.js.map +1 -1
  48. package/dist/Budgets/SimpleBudget.d.ts +2 -2
  49. package/dist/Budgets/SimpleBudget.d.ts.map +1 -1
  50. package/dist/Budgets/VestingBudget.d.ts +2 -2
  51. package/dist/Budgets/VestingBudget.d.ts.map +1 -1
  52. package/dist/Deployable/DeployableTarget.cjs +1 -1
  53. package/dist/Deployable/DeployableTarget.cjs.map +1 -1
  54. package/dist/Deployable/DeployableTarget.d.ts +6 -6
  55. package/dist/Deployable/DeployableTarget.d.ts.map +1 -1
  56. package/dist/Deployable/DeployableTarget.js +22 -17
  57. package/dist/Deployable/DeployableTarget.js.map +1 -1
  58. package/dist/Incentives/AllowListIncentive.cjs +1 -1
  59. package/dist/Incentives/AllowListIncentive.cjs.map +1 -1
  60. package/dist/Incentives/AllowListIncentive.d.ts +2 -2
  61. package/dist/Incentives/AllowListIncentive.d.ts.map +1 -1
  62. package/dist/Incentives/AllowListIncentive.js +17 -13
  63. package/dist/Incentives/AllowListIncentive.js.map +1 -1
  64. package/dist/Incentives/CGDAIncentive.cjs +1 -1
  65. package/dist/Incentives/CGDAIncentive.cjs.map +1 -1
  66. package/dist/Incentives/CGDAIncentive.d.ts +14 -2
  67. package/dist/Incentives/CGDAIncentive.d.ts.map +1 -1
  68. package/dist/Incentives/CGDAIncentive.js +27 -23
  69. package/dist/Incentives/CGDAIncentive.js.map +1 -1
  70. package/dist/Incentives/ERC1155Incentive.d.ts +2 -2
  71. package/dist/Incentives/ERC1155Incentive.d.ts.map +1 -1
  72. package/dist/Incentives/ERC20Incentive.cjs +1 -1
  73. package/dist/Incentives/ERC20Incentive.cjs.map +1 -1
  74. package/dist/Incentives/ERC20Incentive.d.ts +2 -2
  75. package/dist/Incentives/ERC20Incentive.d.ts.map +1 -1
  76. package/dist/Incentives/ERC20Incentive.js +17 -13
  77. package/dist/Incentives/ERC20Incentive.js.map +1 -1
  78. package/dist/Incentives/ERC20VariableIncentive.d.ts +2 -2
  79. package/dist/Incentives/ERC20VariableIncentive.d.ts.map +1 -1
  80. package/dist/Incentives/Incentive.cjs +1 -1
  81. package/dist/Incentives/Incentive.cjs.map +1 -1
  82. package/dist/Incentives/Incentive.js +34 -30
  83. package/dist/Incentives/Incentive.js.map +1 -1
  84. package/dist/Incentives/PointsIncentive.cjs +1 -1
  85. package/dist/Incentives/PointsIncentive.cjs.map +1 -1
  86. package/dist/Incentives/PointsIncentive.d.ts +2 -2
  87. package/dist/Incentives/PointsIncentive.d.ts.map +1 -1
  88. package/dist/Incentives/PointsIncentive.js +13 -9
  89. package/dist/Incentives/PointsIncentive.js.map +1 -1
  90. package/dist/{SimpleDenyList-4PtOPXTc.js → SimpleDenyList-C21O9Yfi.js} +23 -19
  91. package/dist/SimpleDenyList-C21O9Yfi.js.map +1 -0
  92. package/dist/SimpleDenyList-DeJRKD2D.cjs +2 -0
  93. package/dist/{SimpleDenyList-4PtOPXTc.js.map → SimpleDenyList-DeJRKD2D.cjs.map} +1 -1
  94. package/dist/Validators/SignerValidator.cjs +1 -1
  95. package/dist/Validators/SignerValidator.cjs.map +1 -1
  96. package/dist/Validators/SignerValidator.d.ts +2 -2
  97. package/dist/Validators/SignerValidator.d.ts.map +1 -1
  98. package/dist/Validators/SignerValidator.js +18 -14
  99. package/dist/Validators/SignerValidator.js.map +1 -1
  100. package/dist/Validators/Validator.cjs +1 -1
  101. package/dist/Validators/Validator.js +1 -1
  102. package/dist/deployments-BvFcK_eR.js +40 -0
  103. package/dist/deployments-BvFcK_eR.js.map +1 -0
  104. package/dist/deployments-Ho4PnGCS.cjs +2 -0
  105. package/dist/deployments-Ho4PnGCS.cjs.map +1 -0
  106. package/dist/deployments.json +38 -0
  107. package/dist/errors.cjs +1 -1
  108. package/dist/errors.cjs.map +1 -1
  109. package/dist/errors.d.ts +122 -20
  110. package/dist/errors.d.ts.map +1 -1
  111. package/dist/errors.js +98 -28
  112. package/dist/errors.js.map +1 -1
  113. package/dist/{generated-BDeDiaCK.js → generated-LpgSHrH0.js} +150 -110
  114. package/dist/generated-LpgSHrH0.js.map +1 -0
  115. package/dist/generated-tq_HLZJ0.cjs +3 -0
  116. package/dist/generated-tq_HLZJ0.cjs.map +1 -0
  117. package/dist/index.cjs +1 -1
  118. package/dist/index.js +115 -108
  119. package/dist/utils.cjs +1 -1
  120. package/dist/utils.cjs.map +1 -1
  121. package/dist/utils.d.ts +25 -11
  122. package/dist/utils.d.ts.map +1 -1
  123. package/dist/utils.js +38 -23
  124. package/dist/utils.js.map +1 -1
  125. package/package.json +10 -6
  126. package/src/Actions/Action.test.ts +8 -4
  127. package/src/Actions/ContractAction.ts +5 -3
  128. package/src/Actions/ERC721MintAction.ts +5 -3
  129. package/src/Actions/EventAction.test.ts +528 -100
  130. package/src/Actions/EventAction.ts +302 -60
  131. package/src/AllowLists/AllowList.test.ts +1 -1
  132. package/src/AllowLists/SimpleAllowList.ts +6 -3
  133. package/src/AllowLists/SimpleDenyList.ts +6 -3
  134. package/src/BoostCore.test.ts +31 -91
  135. package/src/BoostCore.ts +137 -34
  136. package/src/BoostRegistry.ts +89 -21
  137. package/src/Budgets/ManagedBudget.ts +6 -4
  138. package/src/Budgets/SimpleBudget.ts +4 -3
  139. package/src/Budgets/VestingBudget.ts +4 -3
  140. package/src/Deployable/DeployableTarget.ts +22 -11
  141. package/src/Incentives/AllowListIncentive.ts +6 -3
  142. package/src/Incentives/CGDAIncentive.ts +6 -3
  143. package/src/Incentives/ERC1155Incentive.ts +4 -3
  144. package/src/Incentives/ERC20Incentive.ts +6 -3
  145. package/src/Incentives/ERC20VariableIncentive.ts +6 -3
  146. package/src/Incentives/PointsIncentive.ts +6 -3
  147. package/src/Validators/SignerValidator.ts +6 -3
  148. package/src/errors.ts +177 -21
  149. package/src/utils.ts +60 -11
  150. package/dist/SimpleDenyList-CqT0BMP7.cjs +0 -2
  151. package/dist/SimpleDenyList-CqT0BMP7.cjs.map +0 -1
  152. package/dist/generated-BDeDiaCK.js.map +0 -1
  153. package/dist/generated-wKBNvm48.cjs +0 -3
  154. package/dist/generated-wKBNvm48.cjs.map +0 -1
@@ -7,28 +7,41 @@ import {
7
7
  } from '@boostxyz/evm';
8
8
  import { bytecode } from '@boostxyz/evm/artifacts/contracts/actions/EventAction.sol/EventAction.json';
9
9
  import events from '@boostxyz/signatures/events';
10
+ import functions from '@boostxyz/signatures/functions';
10
11
  import {
11
12
  type Abi,
12
13
  type AbiEvent,
14
+ type AbiFunction,
13
15
  type Address,
14
16
  type ContractEventName,
17
+ type ContractFunctionName,
18
+ type GetLogsReturnType,
19
+ type GetTransactionParameters,
15
20
  type Hex,
16
21
  type Log,
22
+ type PublicClient,
23
+ decodeFunctionData,
17
24
  encodeAbiParameters,
25
+ fromHex,
18
26
  isAddressEqual,
27
+ trim,
19
28
  } from 'viem';
20
29
  import { getLogs } from 'viem/actions';
30
+ import { EventAction as EventActionBases } from '../../dist/deployments.json';
21
31
  import type {
22
32
  DeployableOptions,
23
33
  GenericDeployableParams,
24
34
  } from '../Deployable/Deployable';
25
35
  import { DeployableTarget } from '../Deployable/DeployableTarget';
26
36
  import {
37
+ DecodedArgsMalformedError,
27
38
  FieldValueNotComparableError,
28
39
  FieldValueUndefinedError,
40
+ FunctionDataDecodeError,
29
41
  InvalidNumericalCriteriaError,
30
42
  NoEventActionStepsProvidedError,
31
43
  TooManyEventActionStepsProvidedError,
44
+ UnparseableAbiParamError,
32
45
  UnrecognizedFilterTypeError,
33
46
  } from '../errors';
34
47
  import {
@@ -55,6 +68,7 @@ export enum FilterType {
55
68
  GREATER_THAN = 2,
56
69
  LESS_THAN = 3,
57
70
  CONTAINS = 4,
71
+ REGEX = 5,
58
72
  }
59
73
 
60
74
  /**
@@ -198,6 +212,41 @@ export interface ActionStep {
198
212
  */
199
213
  actionParameter: Criteria;
200
214
  }
215
+
216
+ /**
217
+ * Parameters for validating an event step.
218
+ *
219
+ * This type omits the 'address' field from GetLogsParams and adds optional fields
220
+ * for logs and known events.
221
+ *
222
+ * @typedef {Object} ValidateEventStepParams
223
+ * @property {Log[]} [logs]
224
+ * @property {Record<Hex, AbiEvent>} [knownEvents]
225
+ * @property {number} [fromBlock]
226
+ * @property {number} [toBlock]
227
+ * @property {Hex} [blockHash]
228
+ * @property {Abi} abi
229
+ * @property {ContractEventName<Abi>} eventName
230
+ */
231
+ export type ValidateEventStepParams = Omit<
232
+ GetLogsParams<Abi, ContractEventName<Abi>> & {
233
+ logs?: Log[];
234
+ knownEvents?: Record<Hex, AbiEvent>;
235
+ },
236
+ 'address'
237
+ >;
238
+
239
+ /**
240
+ * Parameters for validating a function step.
241
+ *
242
+ * This type includes all parameters required to get a transaction.
243
+ *
244
+ * @typedef {Object} ValidateFunctionStepParams
245
+ * @property {Hex} hash
246
+ * @property {number} [chainId]
247
+ */
248
+ export type ValidateFunctionStepParams = GetTransactionParameters;
249
+
201
250
  /**
202
251
  * You can either supply a simplified version of the payload, or one that explicitly declares action steps.
203
252
  *
@@ -280,6 +329,26 @@ export interface EventActionPayloadRaw {
280
329
  actionStepFour: ActionStep;
281
330
  }
282
331
 
332
+ /**
333
+ * Array of event logs to pass into TxParams
334
+ * @export
335
+ * @typedef {EventLogs}
336
+ */
337
+ export type EventLogs = GetLogsReturnType<AbiEvent, AbiEvent[], true>;
338
+
339
+ /**
340
+ * Getter params from the event action contract
341
+ *
342
+ * @export
343
+ * @typedef {ReadEventActionParams}
344
+ * @param {fnName} fnName - The getter function name
345
+ */
346
+ export type ReadEventActionParams<
347
+ fnName extends ContractFunctionName<typeof eventActionAbi, 'pure' | 'view'>,
348
+ > = ReadParams<typeof eventActionAbi, fnName>;
349
+
350
+ type TxParams = ValidateEventStepParams | ValidateFunctionStepParams;
351
+
283
352
  /**
284
353
  * A generic event action
285
354
  *
@@ -305,9 +374,12 @@ export class EventAction extends DeployableTarget<
305
374
  *
306
375
  * @public
307
376
  * @static
308
- * @type {Address}
377
+ * @type {Record<number, Address>}
309
378
  */
310
- public static override base: Address = import.meta.env.VITE_EVENT_ACTION_BASE;
379
+ public static override bases: Record<number, Address> = {
380
+ ...(EventActionBases as Record<number, Address>),
381
+ 31337: import.meta.env.VITE_EVENT_ACTION_BASE,
382
+ };
311
383
  /**
312
384
  * @inheritdoc
313
385
  *
@@ -323,12 +395,12 @@ export class EventAction extends DeployableTarget<
323
395
  * @public
324
396
  * @async
325
397
  * @param {number} index The index of the action event to retrieve
326
- * @param {?ReadParams<typeof eventActionAbi, 'getActionStep'>} [params]
398
+ * @param {?ReadEventActionParams<'getActionStep'>} [params]
327
399
  * @returns {Promise<ActionStep>}
328
400
  */
329
401
  public async getActionStep(
330
402
  index: number,
331
- params?: ReadParams<typeof eventActionAbi, 'getActionStep'>,
403
+ params?: ReadEventActionParams<'getActionStep'>,
332
404
  ) {
333
405
  const steps = await this.getActionSteps(params);
334
406
  return steps.at(index);
@@ -339,11 +411,11 @@ export class EventAction extends DeployableTarget<
339
411
  *
340
412
  * @public
341
413
  * @async
342
- * @param {?ReadParams<typeof eventActionAbi, 'getActionSteps'>} [params]
414
+ * @param {?ReadEventActionParams<'getActionSteps'>} [params]
343
415
  * @returns {Promise<ActionStep[]>}
344
416
  */
345
417
  public async getActionSteps(
346
- params?: ReadParams<typeof eventActionAbi, 'getActionSteps'>,
418
+ params?: ReadEventActionParams<'getActionSteps'>,
347
419
  ) {
348
420
  const steps = (await readEventActionGetActionSteps(this._config, {
349
421
  address: this.assertValidAddress(),
@@ -359,11 +431,11 @@ export class EventAction extends DeployableTarget<
359
431
  *
360
432
  * @public
361
433
  * @async
362
- * @param {?ReadParams<typeof eventActionAbi, 'getActionStepsCount'>} [params]
434
+ * @param {?ReadEventActionParams<'getActionStepsCount'>} [params]
363
435
  * @returns {Promise<bigint>}
364
436
  */
365
437
  public async getActionStepsCount(
366
- params?: ReadParams<typeof eventActionAbi, 'getActionStepsCount'>,
438
+ params?: ReadEventActionParams<'getActionStepsCount'>,
367
439
  ) {
368
440
  const steps = await this.getActionSteps(params);
369
441
  return steps.length;
@@ -374,17 +446,16 @@ export class EventAction extends DeployableTarget<
374
446
  *
375
447
  * @public
376
448
  * @async
377
- * @param {?ReadParams<typeof eventActionAbi, 'getActionClaimant'>} [params]
449
+ * @param {?ReadEventActionParams<'getActionClaimant'>} [params]
378
450
  * @returns {Promise<ActionClaimant>}
379
451
  */
380
452
  public async getActionClaimant(
381
- params?: ReadParams<typeof eventActionAbi, 'getActionClaimant'>,
453
+ params?: ReadEventActionParams<'getActionClaimant'>,
382
454
  ) {
383
455
  const result = (await readEventActionGetActionClaimant(this._config, {
384
456
  address: this.assertValidAddress(),
385
457
  ...this.optionallyAttachAccount(),
386
- // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
387
- ...(params as any),
458
+ ...params,
388
459
  })) as RawActionClaimant;
389
460
  return _fromRawActionStep(result);
390
461
  }
@@ -435,21 +506,11 @@ export class EventAction extends DeployableTarget<
435
506
  *
436
507
  * @public
437
508
  * @async
438
- * @param {?ReadParams<typeof eventActionAbi, 'getActionSteps'> &
439
- * GetLogsParams<Abi, ContractEventName<Abi>> & {
440
- * knownEvents?: Record<Hex, AbiEvent>;
441
- * logs?: Log[];
442
- * }} [params]
509
+ * @param {?TxParams} [params]
443
510
  * @returns {Promise<boolean>}
444
511
  */
445
- public async validateActionSteps(
446
- params?: ReadParams<typeof eventActionAbi, 'getActionSteps'> &
447
- GetLogsParams<Abi, ContractEventName<Abi>> & {
448
- knownEvents?: Record<Hex, AbiEvent>;
449
- logs?: Log[];
450
- },
451
- ) {
452
- const actionSteps = await this.getActionSteps(params);
512
+ public async validateActionSteps(params?: TxParams) {
513
+ const actionSteps = await this.getActionSteps();
453
514
  for (const actionStep of actionSteps) {
454
515
  if (!(await this.isActionStepValid(actionStep, params))) {
455
516
  return false;
@@ -459,24 +520,45 @@ export class EventAction extends DeployableTarget<
459
520
  }
460
521
 
461
522
  /**
462
- * Validates a single action step with a given criteria against logs.
463
- * If logs are provided in the optional `params` argument, then those logs will be used instead of fetched with the configured client.
523
+ * Validates a single action step with a given criteria against logs or function calls.
524
+ * If logs are provided in the optional `params` argument, then those logs will be used instead of being fetched with the configured client.
525
+ * For functions a hash is required.
464
526
  *
465
527
  * @public
466
528
  * @async
467
- * @param {ActionStep} actionStep
468
- * @param {?GetLogsParams<Abi, ContractEventName<Abi>> & {
469
- * knownEvents?: Record<Hex, AbiEvent>;
470
- * logs?: Log[];
471
- * }} [params]
529
+ * @param {ActionStep} actionStep - The action step to validate. Can be a function of event step.
530
+ * @param {?TxParams & { chainId?: number }} [params] - Additional parameters for validation, including known events, logs, and chain ID.
472
531
  * @returns {Promise<boolean>}
473
532
  */
474
533
  public async isActionStepValid(
475
534
  actionStep: ActionStep,
476
- params?: GetLogsParams<Abi, ContractEventName<Abi>> & {
477
- knownEvents?: Record<Hex, AbiEvent>;
478
- logs?: Log[];
479
- },
535
+ params?: TxParams & { chainId?: number },
536
+ ) {
537
+ if (actionStep.signatureType === SignatureType.EVENT) {
538
+ return await this.isActionEventValid(actionStep, params);
539
+ }
540
+ if (actionStep.signatureType === SignatureType.FUNC) {
541
+ return await this.isActionFunctionValid(
542
+ actionStep,
543
+ params as ValidateFunctionStepParams,
544
+ );
545
+ }
546
+ return false;
547
+ }
548
+
549
+ /**
550
+ * Validates a single action event with a given criteria against logs.
551
+ * If logs are provided in the optional `params` argument, then those logs will be used instead of being fetched with the configured client.
552
+ *
553
+ * @public
554
+ * @async
555
+ * @param {ActionStep} actionStep - The action step containing the event to validate.
556
+ * @param {?ValidateEventStepParams & { chainId?: number }} [params] - Additional parameters for validation, including known events, logs, and chain ID.
557
+ * @returns {Promise<boolean>} Resolves to true if the action event is valid, throws if input is invalid, otherwise false.
558
+ */
559
+ public async isActionEventValid(
560
+ actionStep: ActionStep,
561
+ params?: ValidateEventStepParams & { chainId?: number },
480
562
  ) {
481
563
  const criteria = actionStep.actionParameter;
482
564
  const signature = actionStep.signature;
@@ -487,9 +569,18 @@ export class EventAction extends DeployableTarget<
487
569
  } else {
488
570
  event = (events.abi as Record<Hex, AbiEvent>)[signature] as AbiEvent;
489
571
  }
572
+
490
573
  if (!event) {
491
574
  throw new Error(`No known ABI for given event signature: ${signature}`);
492
575
  }
576
+
577
+ if (this.isArraylikeIndexed(actionStep, event)) {
578
+ // If the field is indexed, we can't filter on it
579
+ throw new UnparseableAbiParamError(
580
+ actionStep.actionParameter.fieldIndex,
581
+ event,
582
+ );
583
+ }
493
584
  const targetContract = actionStep.targetContract;
494
585
  // Get all logs matching the event signature from the target contract
495
586
  const logs =
@@ -502,69 +593,209 @@ export class EventAction extends DeployableTarget<
502
593
  }));
503
594
  if (!logs.length) return false;
504
595
  for (let log of logs) {
505
- if (!this.validateLogAgainstCriteria(criteria, log)) {
596
+ if (!this.validateLogAgainstCriteria(criteria, log as EventLogs[0])) {
506
597
  return false;
507
598
  }
508
599
  }
509
600
  return true;
510
601
  }
602
+ /**
603
+ * Validates a single action function with a given criteria against the transaction input.
604
+ * If a transaction hash is provided in the optional `params` argument, then the transaction
605
+ * will be fetched and decoded using the configured client.
606
+ *
607
+ * @public
608
+ * @async
609
+ * @param {ActionStep} actionStep - The action step containing the function to validate.
610
+ * @param {?ValidateFunctionStepParams & { chainId?: number }} [params] - Additional parameters for validation, including known events, transaction hash, and chain ID.
611
+ * @returns {Promise<boolean>} Resolves to true if the action function is valid, throws if the inputs are invalid, otherwise false.
612
+ */
613
+ public async isActionFunctionValid(
614
+ actionStep: ActionStep,
615
+ params?: ValidateFunctionStepParams & { chainId?: number },
616
+ ) {
617
+ const criteria = actionStep.actionParameter;
618
+ const signature = trim(actionStep.signature);
619
+ if (!params || !params?.hash) {
620
+ // Should we return false in this case?
621
+ throw new Error('Hash is required for function validation');
622
+ }
623
+ const client = this._config.getClient({
624
+ chainId: params?.chainId,
625
+ }) as PublicClient;
626
+ // Fetch the transaction receipt and decode the function input using `viem` utilities
627
+ const transaction = await client.getTransaction({ hash: params.hash });
628
+ const func = (functions.abi as Record<Hex, AbiFunction>)[
629
+ signature
630
+ ] as AbiFunction;
631
+
632
+ if (!func) {
633
+ throw new Error(
634
+ `No known ABI for given function signature: ${signature}`,
635
+ );
636
+ }
637
+ let decodedData;
638
+ try {
639
+ decodedData = decodeFunctionData({
640
+ abi: [func],
641
+ data: transaction.input,
642
+ });
643
+ } catch (e) {
644
+ throw new FunctionDataDecodeError([func], e as Error);
645
+ }
511
646
 
647
+ // Validate the criteria against decoded arguments using fieldIndex
648
+ const decodedArgs = decodedData.args;
649
+
650
+ if (!decodedArgs || !decodedData) return false;
651
+
652
+ if (
653
+ !this.validateFunctionAgainstCriteria(
654
+ criteria,
655
+ decodedArgs as (string | bigint)[],
656
+ )
657
+ ) {
658
+ return false;
659
+ }
660
+
661
+ return true;
662
+ }
512
663
  /**
513
- * Validates a {@link Log} against a given criteria.
664
+ * Validates a field against a given criteria.
514
665
  *
515
666
  * @param {Criteria} criteria - The criteria to validate against.
516
- * @param {Log} log - The Viem event log.
517
- * @returns {boolean} - Returns true if the log passes the criteria, false otherwise.
667
+ * @param {string | bigint} fieldValue - The field value to validate.
668
+ * @returns {Promise<boolean>} - Returns true if the field passes the criteria, false otherwise.
518
669
  */
519
- public validateLogAgainstCriteria(criteria: Criteria, log: Log) {
520
- const fieldValue = log.topics.at(criteria.fieldIndex);
521
- if (fieldValue === undefined) {
522
- throw new FieldValueUndefinedError({ log, criteria, fieldValue });
523
- }
670
+ public validateFieldAgainstCriteria(
671
+ criteria: Criteria,
672
+ fieldValue: string | bigint | Hex,
673
+ input:
674
+ | { log: EventLogs[0] }
675
+ | { decodedArgs: readonly (string | bigint)[] },
676
+ ): boolean {
524
677
  // Type narrow based on criteria.filterType
525
678
  switch (criteria.filterType) {
526
679
  case FilterType.EQUAL:
527
680
  if (criteria.fieldType === PrimitiveType.ADDRESS) {
528
- return isAddressEqual(
529
- criteria.filterData,
530
- `0x${fieldValue.slice(-40)}`,
531
- );
681
+ return isAddressEqual(criteria.filterData, fieldValue as Address);
532
682
  }
533
683
  return fieldValue === criteria.filterData;
534
684
 
535
685
  case FilterType.NOT_EQUAL:
536
- if (criteria.fieldType === PrimitiveType.ADDRESS) {
537
- return !isAddressEqual(
538
- criteria.filterData,
539
- `0x${fieldValue.slice(-40)}`,
540
- );
541
- }
542
686
  return fieldValue !== criteria.filterData;
543
687
 
544
688
  case FilterType.GREATER_THAN:
545
689
  if (criteria.fieldType === PrimitiveType.UINT) {
546
690
  return BigInt(fieldValue) > BigInt(criteria.filterData);
547
691
  }
548
- throw new InvalidNumericalCriteriaError({ log, criteria, fieldValue });
692
+ throw new InvalidNumericalCriteriaError({
693
+ ...input,
694
+ criteria,
695
+ fieldValue,
696
+ });
549
697
 
550
698
  case FilterType.LESS_THAN:
551
699
  if (criteria.fieldType === PrimitiveType.UINT) {
552
700
  return BigInt(fieldValue) < BigInt(criteria.filterData);
553
701
  }
554
- throw new InvalidNumericalCriteriaError({ log, criteria, fieldValue });
702
+ throw new InvalidNumericalCriteriaError({
703
+ ...input,
704
+ criteria,
705
+ fieldValue,
706
+ });
555
707
 
556
708
  case FilterType.CONTAINS:
557
709
  if (
558
710
  criteria.fieldType === PrimitiveType.BYTES ||
559
711
  criteria.fieldType === PrimitiveType.STRING
560
712
  ) {
561
- return fieldValue.includes(criteria.filterData);
713
+ let substring;
714
+ if (criteria.fieldType === PrimitiveType.STRING) {
715
+ substring = fromHex(criteria.filterData, 'string');
716
+ } else {
717
+ // truncate the `0x` prefix
718
+ substring = criteria.filterData.slice(2);
719
+ }
720
+ return (fieldValue as string).includes(substring);
721
+ }
722
+ throw new FieldValueNotComparableError({
723
+ ...input,
724
+ criteria,
725
+ fieldValue,
726
+ });
727
+
728
+ case FilterType.REGEX:
729
+ if (typeof fieldValue !== 'string') {
730
+ throw new FieldValueNotComparableError({
731
+ ...input,
732
+ criteria,
733
+ fieldValue,
734
+ });
735
+ }
736
+
737
+ if (criteria.fieldType === PrimitiveType.STRING) {
738
+ // fieldValue is decoded by the ABI
739
+ const regexString = fromHex(criteria.filterData, 'string');
740
+ return new RegExp(regexString).test(fieldValue);
562
741
  }
563
- throw new FieldValueNotComparableError({ log, criteria, fieldValue });
564
742
 
565
743
  default:
566
- throw new UnrecognizedFilterTypeError({ log, criteria, fieldValue });
744
+ throw new UnrecognizedFilterTypeError({
745
+ ...input,
746
+ criteria,
747
+ fieldValue,
748
+ });
749
+ }
750
+ }
751
+
752
+ /**
753
+ * Validates a {@link Log} against a given criteria.
754
+ *
755
+ * @param {Criteria} criteria - The criteria to validate against.
756
+ * @param {Log} log - The Viem event log.
757
+ * @returns {Promise<boolean>} - Returns true if the log passes the criteria, false otherwise.
758
+ */
759
+ public validateLogAgainstCriteria(
760
+ criteria: Criteria,
761
+ log: EventLogs[0],
762
+ ): boolean {
763
+ if (!Array.isArray(log.args) || log.args.length <= criteria.fieldIndex) {
764
+ throw new DecodedArgsMalformedError({
765
+ log,
766
+ criteria,
767
+ fieldValue: undefined,
768
+ });
769
+ }
770
+
771
+ const fieldValue = log.args.at(criteria.fieldIndex);
772
+ if (fieldValue === undefined) {
773
+ throw new FieldValueUndefinedError({ log, criteria, fieldValue });
567
774
  }
775
+ return this.validateFieldAgainstCriteria(criteria, fieldValue, { log });
776
+ }
777
+
778
+ /**
779
+ * Validates a function's decoded arguments against a given criteria.
780
+ *
781
+ * @param {Criteria} criteria - The criteria to validate against.
782
+ * @param {unknown[]} decodedArgs - The decoded arguments of the function call.
783
+ * @returns {Promise<boolean>} - Returns true if the decoded argument passes the criteria, false otherwise.
784
+ */
785
+ public validateFunctionAgainstCriteria(
786
+ criteria: Criteria,
787
+ decodedArgs: readonly (string | bigint)[],
788
+ ): boolean {
789
+ const fieldValue = decodedArgs[criteria.fieldIndex];
790
+ if (fieldValue === undefined) {
791
+ throw new FieldValueUndefinedError({
792
+ criteria,
793
+ fieldValue,
794
+ });
795
+ }
796
+ return this.validateFieldAgainstCriteria(criteria, fieldValue, {
797
+ decodedArgs,
798
+ });
568
799
  }
569
800
 
570
801
  /**
@@ -615,6 +846,17 @@ export class EventAction extends DeployableTarget<
615
846
  ...this.optionallyAttachAccount(options.account),
616
847
  };
617
848
  }
849
+
850
+ public isArraylikeIndexed(step: ActionStep, event: AbiEvent) {
851
+ if (
852
+ (step.actionParameter.fieldType === PrimitiveType.STRING ||
853
+ step.actionParameter.fieldType === PrimitiveType.BYTES) &&
854
+ event.inputs[step.actionParameter.fieldIndex]?.indexed
855
+ ) {
856
+ return true;
857
+ }
858
+ return false;
859
+ }
618
860
  }
619
861
 
620
862
  function _dedupeActionSteps(_steps: ActionStep[]): ActionStep[] {
@@ -52,7 +52,7 @@ describe('AllowList', () => {
52
52
  ).toBeInstanceOf(SimpleAllowList);
53
53
  });
54
54
 
55
- test('can automatically instantiate SimpleAllowList given an address', async () => {
55
+ test('can automatically instantiate SimpleDenyList given an address', async () => {
56
56
  const _allowList = await loadFixture(freshDenyList(fixtures));
57
57
  expect(
58
58
  await allowListFromAddress(
@@ -16,6 +16,7 @@ import {
16
16
  zeroAddress,
17
17
  zeroHash,
18
18
  } from 'viem';
19
+ import { SimpleAllowList as SimpleAllowListBases } from '../../dist/deployments.json';
19
20
  import type {
20
21
  DeployableOptions,
21
22
  GenericDeployableParams,
@@ -92,10 +93,12 @@ export class SimpleAllowList extends DeployableTarget<
92
93
  *
93
94
  * @public
94
95
  * @static
95
- * @type {Address}
96
+ * @type {Record<number, Address>}
96
97
  */
97
- public static override base: Address = import.meta.env
98
- .VITE_SIMPLE_ALLOWLIST_BASE;
98
+ public static override bases: Record<number, Address> = {
99
+ ...(SimpleAllowListBases as Record<number, Address>),
100
+ 31337: import.meta.env.VITE_SIMPLE_ALLOWLIST_BASE,
101
+ };
99
102
  /**
100
103
  * @inheritdoc
101
104
  *
@@ -14,6 +14,7 @@ import {
14
14
  zeroAddress,
15
15
  zeroHash,
16
16
  } from 'viem';
17
+ import { SimpleDenyList as SimpleDenyListBases } from '../../dist/deployments.json';
17
18
  import type {
18
19
  DeployableOptions,
19
20
  GenericDeployableParams,
@@ -83,10 +84,12 @@ export class SimpleDenyList<
83
84
  *
84
85
  * @public
85
86
  * @static
86
- * @type {Address}
87
+ * @type {Record<number, Address>}
87
88
  */
88
- public static override base: Address = import.meta.env
89
- .VITE_SIMPLE_DENYLIST_BASE;
89
+ public static override bases: Record<number, Address> = {
90
+ ...(SimpleDenyListBases as Record<number, Address>),
91
+ 31337: import.meta.env.VITE_SIMPLE_DENYLIST_BASE,
92
+ };
90
93
  /**
91
94
  * @inheritdoc
92
95
  *